让GtkListStore支持数据延迟加载的构想
让GtkListStore支持数据延迟加载的构想
转载时请注明出处:http://blog.csdn.net/absurd/
最近遇到一个问题,在名片列表中要显示全部名片,我们最大名片条数限制是5000条,一下子全部检索过来会非常慢。为了解决这类问题,我们在数据库封装层做了优化,即使全部检索了,但它只从数据库中取前30条,其余数据直到应用程序使用时才从数据库中获取,这种延迟加载的方式会有更好的性能表现。
现在才发现数据库封装层做了优化还不够,原因是GtkTreeView(也可以用来实现ListBox)不支持像Win32下的ListBox所具有Ownerdraw(自绘)功能,它需要在开始时就加载所有数据,结果仍然无法实现延迟加载,数据库封装层做的优化失去了效果。
为了解决这个问题,需要对GtkListStore改造。分析相关源代码后,我们发现:
1. GtkTreeView/GtkTreeModel采用了MVC模型。GtkTreeView是view,负责显示控制,而GtkTreeModel是model,负责数据管理。
2. GtkTreeModel只是个接口,它有两种实现,GtkListStore和GtkTreeStore,它们分别实现了List和Tree的数据管理。
3. 为了支持不同的数据表现形式,GtkTreeView并不负责每个具体项(Item)的绘制,具体项的绘制由GtkCellRenderer完成。GtkCellRenderer有几种不同的实现方式:GtkCellRendererText、GtkCellRendererPixbuf、GtkCellRendererToggle、GtkCellRendererCombo和GtkCellRendererProgress。
4. 在控件显示时,GtkTreeView负责从GtkTreeModel中获得数据,然后把数据传递给GtkCellRenderer,并调用GtkCellRenderer的函数去绘制。
很容易想到:在创建时,向GtkTreeModel加入假数据(如记录序号),直到GtkTreeView向GtkTreeModel索取数据时,才从数据库获取。但遇到两个问题:
1. GtkTreeView和所有GtkWidget一样,先要在size_request里计算控件的大小,这里它要把每一项的get_value调用一遍,也就是说在显示之前仍然要把所有数据取出来。
2. 重载GtkTreeModel的get_value函数比较困难。麻烦在于GtkTreeModelIface是个接口,GtkListStore实现了它,它不像普通虚函数可以重载。对于glib接口,你只能去实现这个接口,而不能重载接口的一个函数。
对于第一个问题,我们做了些简化处理,因为我们列表中的所有项的高度及宽度一样,在size_request阶段调用get_value时,可以返回一个默认值,说以便GtkTreeView可以计算控件大小。
对于第二个问题,我们决定对GtkListStore扩展,而不是重载。让应用程序可以hook对GtkListStore的get_value函数的调用。这很简单,设置一个回调函数就行了。
做了简单测试,证明此方案可行,但还需要进一步验证。此方案虽然可行,但不够优雅,不知道大家有什么好办法没有。
~~end~~