我用wxpython和ulc为个人数据库写了一个小python程序。 我以为我已经完成并最终从原始访问数据库导入了所有数据,现在遇到了问题。在ulc中有近1000个条目(而不是开发中的50个)会减慢它的速度,因此变得无法使用。 所以我开始使用虚拟模式重写所有内容来解决这个问题。但现在我面临另一个问题。
我在listctrl中有一个复选框来选择多个人,我也使用ColumnSorterMixin。在正常模式下,以不同的方式对列表进行排序时,列表中的选择将保持正确,但在虚拟模式下,选择将保留在行而不是真实项目上。
例如,如果您选择第三行然后求助列表,则第三行中的项目现在位于第四行,但仍然选择第三行。难道我做错了什么?我尝试使用ctrl键复选框和选择。两者都有同样的问题。
这是我的问题测试代码......
import wx
from wx.lib.agw import ultimatelistctrl as ULC
import wx.lib.mixins.listctrl as listmix
data = {
1 : ("John Doe", "Madeup Road 11\nFakeTown", "000-383783763"),
2 : ("Jane Doe", "Madeup Road 11\nFakeTown", "000-383783763"),
3 : ("Max Mustermann", "Madeup Road 16\nFakeTown", "043-3434763"),
4 : ("Myself", "Fake Road 9\nFakeTown", "323-3843457773"),
}
class mylist(ULC.UltimateListCtrl, listmix.ColumnSorterMixin):
def __init__(self, parent):
ULC.UltimateListCtrl.__init__(self, parent, -1, agwStyle=ULC.ULC_VIRTUAL|ULC.ULC_REPORT|ULC.ULC_USER_ROW_HEIGHT|ULC.ULC_SINGLE_SEL|ULC.ULC_VRULES|ULC.ULC_HRULES)
self.SetUserLineHeight(40)
self.itemDataMap = data
self.itemIndexMap = data.keys()
self.SetItemCount(len(data))
self.table_fields=['Name','Street','Phone']
field_index=0
for field in self.table_fields:
info = ULC.UltimateListItem()
info._mask = wx.LIST_MASK_TEXT | wx.LIST_MASK_IMAGE | wx.LIST_MASK_FORMAT
info._image = []
info._format = wx.LIST_FORMAT_LEFT
info._kind = 1
info._text = field
info._font= wx.Font(13, wx.ROMAN, wx.NORMAL, wx.BOLD)
self.InsertColumnInfo(field_index, info)
self.SetColumnWidth(field_index,175)
field_index += 1
self.checked = []
self.Bind(ULC.EVT_LIST_ITEM_CHECKING, self.OnCheck)
self.Bind(wx.EVT_LIST_COL_CLICK, self.OnColumn)
#mixins
listmix.ColumnSorterMixin.__init__(self, 3)
#sort by column (2), A->Z ascending order (1)
self.SortListItems(0, 1)
def SortItems(self,sorter=cmp):
items = list(self.itemDataMap.keys())
items.sort(sorter)
self.itemIndexMap = items
# redraw the list
self.Refresh()
def OnColumn(self, e):
self.Update()
e.Skip()
def GetListCtrl(self):
return self
def OnCheck(self, event):
item_column = (event.m_itemIndex, event.m_item.GetColumn())
print item_column
try:
idx = self.checked.index(item_column)
except ValueError:
idx = None
if idx == None:
self.checked.append(item_column)
else:
del(self.checked[idx])
self.Refresh()
def getColumnText(self, index, col):
item = self.GetItem(index, col)
return item.GetText()
def OnGetItemText(self, item, col):
index=self.itemIndexMap[item]
s = self.itemDataMap[index][col]
return s
def OnGetItemColumnImage(self, item, col):
return []
def OnGetItemImage(self, item):
return []
def OnGetItemAttr(self, item):
return None
def OnGetItemTextColour(self, item, col):
return None
def OnGetItemToolTip(self, item, col):
return None
def OnGetItemKind(self, item):
return 1
def OnGetItemColumnKind(self, item, col):
if col==0:
return self.OnGetItemKind(item)
return 0
def OnGetItemColumnCheck(self, item, column):
item_column = (item, column)
if item_column in self.checked:
return True
else:
return False
class TestFrame(wx.Frame):
def __init__(self, parent):
wx.Frame.__init__(self, parent, -1, "UltimateListCtrl in wx.LC_VIRTUAL mode", size=(700, 600))
panel = wx.Panel(self, -1)
sizer = wx.BoxSizer(wx.VERTICAL)
self.listctrl = listCtrl = mylist(panel)
sizer.Add(listCtrl, 1, wx.EXPAND)
panel.SetSizer(sizer)
sizer.Layout()
self.CenterOnScreen()
self.Show()
class MyApp(wx.App):
def OnInit(self):
frame = TestFrame(None)
frame.Show(True)
return True
app = MyApp(0)
app.MainLoop()
这可能是在虚拟ListCtrl中还是我做错了什么?
我在Windows 8.1,Python 2.7.10和wxPython 3.0.2.0上测试它。
答案 0 :(得分:0)
编辑注意到你在3.0.2上测试,所以我从之前更新了我的演示并使用相同的wx版本(和Python 2.7.11)而不是wx 3.0.3'Phoenix'进行了测试我正在使用。
你问的答案是:是的,这是可能的
不止一种方式可以满足,但是这是一个可以完全粘贴并运行在自己的py文件中进行测试的工作演示。
此演示在wx版本3.0.2.0 osx-cocoa(经典)上测试,并符合以下条件:
列出一千条记录,在虚拟模式下使用ULC,在任何列上排序,检查多个项目,可以使用全选框检查/取消选中,在排序时保留项目检查而不是保持原位,不会变慢/像您原来的版本一样无法使用。
import wxversion
wxversion.select(['3.0']) #for me this switches from 'Phoenix' to 'Classic'
import wx; print wx.version();
from wx.lib.agw import ultimatelistctrl as ULC
from wx.lib.mixins import listctrl as listmix
class mylist(ULC.UltimateListCtrl, listmix.ColumnSorterMixin):
"""
Sortable list with check box for each row and a 'select all' box
When sorting, the checkboxes follow the data, rather than staying on their row
"""
def __init__(self, parent):
ULC.UltimateListCtrl.__init__(self, parent, -1,
agwStyle=ULC.ULC_VIRTUAL | ULC.ULC_REPORT# | ULC_SINGLE_SEL
)
datasource = Records()
self.itemDataMap = datasource.data
self.itemIndexMap = self.itemDataMap.keys()
self.itemCheckedMap1 = set()
self.itemCheckedMap2 = set()
self.table_fields = ["id", "rockcol", "papercol", "scissorscol", "lizardcol"]
field_index = 0
for field in self.table_fields:
info = ULC.UltimateListItem()
masktoset = ULC.ULC_MASK_TEXT
if field_index == 0:
masktoset |= ULC.ULC_MASK_KIND | ULC.ULC_MASK_CHECK
kindtoset = ULC.ULC_KIND_CHECK = wx.ITEM_CHECK
widthtoset = 60
info.Check(False)
else:
widthtoset = ULC.ULC_AUTOSIZE
info.SetText(field)
info.SetKind(kindtoset)
info.SetMask(masktoset)
self.InsertColumnInfo(field_index, info)
self.SetItemCount(len(datasource.data))
self.SetColumnWidth(field_index, widthtoset)
field_index += 1
self.Bind(ULC.EVT_LIST_ITEM_CHECKING, self.OnSetItemCheck)
self.Bind(ULC.EVT_LIST_COL_CHECKING, self.OnSetColumnCheck)
self.Bind(ULC.EVT_LIST_COL_CLICK, self.OnColClick, self)
listmix.ColumnSorterMixin.__init__(self, len(self.table_fields)) #binds col click event
#self.SortListItems(1, 1)
####
# ----------------------------------------------------------------------------
# bound event handling
# ----------------------------------------------------------------------------
def OnSetItemCheck(self, e):
x1 = e.m_itemIndex
y1 = e.EventObject.itemCheckedMap1
x2 = int(e.m_item._text)
y2 = e.EventObject.itemCheckedMap2
for x, y in (x1, y1), (x2, y2):
if x not in y:
y.add(x)
else:
y.remove(x)
self.Refresh()
def OnSetColumnCheck(self, e):
e.EventObject.GetColumn(e.m_col)._checked = x = not e.EventObject.GetColumn(e.m_col)._checked
if x:
e.EventObject.itemCheckedMap1 = set(e.EventObject.itemIndexMap)
else:
e.EventObject.itemCheckedMap1.clear()
self.Refresh()
def OnColClick(self, e):
self.Refresh()
e.Skip()
def GetListCtrl(self): #for sorter init
return self
def SortItems(self, sorter=cmp):
self.itemIndexMap.sort(sorter)
self.Refresh()
def SortListItems(self, col=-1, ascending=1):
self.fix()
super(mylist, self).SortListItems(col, ascending)
def fix(self):
pass
def OnSortOrderChanged(self):
self.itemCheckedMap1 = set(i for i, x in enumerate(self.itemIndexMap) if x in self.itemCheckedMap2)
####
# ----------------------------------------------------------------------------
# overrides for 'virtual' mode support
# ----------------------------------------------------------------------------
def OnGetItemText(self, item, col):
idx = self.itemIndexMap[item]
return str(self.itemDataMap[idx][col])
def OnGetItemTextColour(self, item, col):
return None
def OnGetItemToolTip(self, item, col):
return None
def OnGetItemColumnImage(self, item, column=0):
return []
def OnGetItemCheck(self, idx):
return idx in self.itemCheckedMap1
def OnGetItemColumnCheck(self, item, column=0):
return self.OnGetItemCheck(item)
def OnGetItemKind(self, itemidx):
return wx.ITEM_CHECK
def OnGetItemColumnKind(self, itemidx, columnidx):
if self.GetColumn(columnidx)._kind == wx.ITEM_CHECK:
return self.OnGetItemKind(itemidx)
return wx.ITEM_NORMAL
class Records:
"""
Generates some unsorted data for testing sort and checkbox preservation
"""
def __init__(self):
self.data = {}
self.makedataset(1000)
def makedataset(self, rcount):
for ci in xrange(rcount):
c1 = str(hash(ci^2*2))
c2 = str(hash(ci^3*2))
c3 = str(hash(ci^4*2))
c4 = str(hash(ci^1*2))
self.data[ci] = ci, c1, c2, c3, c4
class TestFrame(wx.Frame):
def __init__(self):
wx.Frame.__init__(self, None, -1, "virtual-mode ULC", size=(800, 300))
panel = wx.Panel(self, -1)
sizer = wx.BoxSizer(wx.VERTICAL)
self.listctrl = mylist(panel)
sizer.Add(self.listctrl, 1, wx.EXPAND)
panel.SetSizer(sizer)
sizer.Layout()
self.Show()
mySandbox = wx.App()
mySandbox.SetTopWindow(TestFrame())
mySandbox.MainLoop()
exit()
使用的策略是每次更改排序顺序时更新选中框的数组。还有其他方法,但这个方法依赖于显示数据中的id列。