我就在这里
分类: Python/Ruby
2013-10-18 09:14:37
让我们设想你的wxPython应用程序需要去显示包含你所有客户的一个列表。开始时你使用一个标准的列表控件,并且它工作的很好。后来人的客户列表变得越来越大,太多的客户使得你的应用程序开始出现了效率问题。这时你的程序起动所需的时间变得较长了,并占用越来越多的内存。你怎么办呢?你可以创建一个虚的列表控件。
问题的实质就是列表控件的数据处理。通常,这些数据都是从数据产生的地方将数据拷贝到列表控件中。这是潜在地浪费资源,对于一个小的列表,这好象看不出任何问题,但对于创建一个较大的列表控件,这将占用很多的内存,并导致启动变慢。
为了将一个列表控件所占的内存和启动所需的时间降到最小化,wxPython允许你去声明一个虚的列表控件,这意味关于每项的信息只在控件需要去显示该项时才生成。这就防止了控件一开始就将每项存储到它的内存空间中,并且这也意味着在启动时,并没有声明完整的列表控件。同时这个方案的缺点就是虚列表中的列表项的恢复可能变得较慢。图13.6显示了一个虚列表。
例13.5显示了产生该虚列表控件的完整代码
图13.6
例13.5 一个虚列表控件
#!/usr/bin/python
#-*- encoding:UTF-8 -*-
import wx
import sys, glob, random
import data
class DataSource:#数据源
"""
A simple data source class that just uses our sample data items.
A real data source class would manage fetching items from a
database or similar.
"""
def GetColumnHeaders(self):
return data.columns
def GetCount(self):
return len(data.rows)
def GetItem(self, index):
return data.rows[index]
def UpdateCache(self, start, end):
pass
class VirtualListCtrl(wx.ListCtrl):#1 声明虚列表
"""
A generic virtual listctrl that fetches data from a DataSource.
"""
def __init__(self, parent, dataSource):
wx.ListCtrl.__init__(self, parent,
style=wx.LC_REPORT|wx.LC_SINGLE_SEL|wx.LC_VIRTUAL)#使用wx.LC_VIRTUAL标记创建虚列表
self.dataSource = dataSource
self.Bind(wx.EVT_LIST_CACHE_HINT, self.DoCacheItems)
self.SetItemCount(dataSource.GetCount())#设置列表的大小
columns = dataSource.GetColumnHeaders()
for col, text in enumerate(columns):
self.InsertColumn(col, text)
def DoCacheItems(self, evt):
self.dataSource.UpdateCache(
evt.GetCacheFrom(), evt.GetCacheTo())
def OnGetItemText(self, item, col):#得到需求时的文本
data = self.dataSource.GetItem(item)
return data[col]
def OnGetItemAttr(self, item): return None
def OnGetItemImage(self, item): return -1
class DemoFrame(wx.Frame):
def __init__(self):
wx.Frame.__init__(self, None, -1,
"Virtual wx.ListCtrl",
size=(600,400))
self.list = VirtualListCtrl(self, DataSource())
app = wx.PySimpleApp()
frame = DemoFrame()
frame.Show()
app.MainLoop()
这个数据源的类是一个简单的例子,它存储了我们所需要的数据项。真实情况下的数据源类还会处理从一个数据库中获取数据之类的情况,这种情况下只需要重新实现本例中的同一接口。
要创建一个虚列表,第一步就是在初始化的时候对列表控件使用wx.LC_VIRTUAL标记如#1。通常使用子类wx.ListCtrl来创建你的虚列表控件,而非仅仅使用构造函数。这是因为你需要覆盖wx.ListCtrl的一些方法,以便扩展这个虚列表。虚列表的声明类似如下:
class MyVirtualList(wx.ListCtrl):
def __init__(self, parent):
wx.ListCtrl.__init__(self, parent, -1,
style=wx.LC_REPORT|wx.LC_VIRTUAL)
有时在虚列表的初始化期间,必须调用SetItemCount()方法。这将告诉控件在数据源中存在多少数据项,这样它就可以设置适当的限制并处理滚动条。如果数据源中的数据项的数量改变了,你可以再调用SetItemCount()一次。你所覆盖的任何以On开关的方法,必须能够处理[0,SetItemCount()-1]间的数据。
你的虚列表控件可以覆盖其父类的三个方法,以便决定在列表控件中显示些什么。最重要的要覆盖的方法是OnGetItemText(item, col)。其中的参数item和col是要绘制的单元格的行和列,方法的返回值是显示在该单元格中的文本字符串。例如,下面的方法将只显示相关单元格的坐标。
def OnGetItemText(self, item, col):
return "Item %d, column %d" % (item, col)
如果你想在一行中显示一个图像,你需要覆盖OnGetItemImage(item)。它的返回值是较早声明的列表控件的图像列中的一个整数索引。如果你没有覆盖这个方法,那么基类版本的OnGetItemImage将返回-1,这表明不显示图像。如果你想改变行的一些显示属性,那么你可以覆盖OnGetItemAttr(item)方法,item是行的索引,该方法返回类wx.ListItemAttr的一个实例。该类有一些get*和set*方法可以用来设置行的颜色、对齐方式等等显示属性。
如果你的虚列表所基于的数据改变了,而你想更新显示,那么你可以使用该列表控件的RefreshItem(item)来重绘特定的行。相关的方法RefreshItems(itemFrom,itemTo)重绘位于索引itemFrom和itemTo间的所有行。 为了对数据源中的数据的获取提供优化帮助,对于要显示一页新的数据,虚列表控件会发送EVT_LIST_CACHE_HINT事件。这将给你的数据源一个时机用以从数据库(或另处)一次获取几个记录并保存它们。这样就使得随后的OnGetItemText()执行的更快。