wxPython - 如何对 ListCtrl 列项目进行排序?
wxPython - How to sort ListCtrl column items?
我正在尝试创建一个 CheckListCtrl,您可以在其中通过单击其 header 对列中的所有数据进行排序。
在我的代码的基本示例中,我将在下面 post 设置 "rows" 作为元组列表,因为在我的最终版本中,ListCtrl 将显示 SQLite 查询的结果。
到目前为止我的代码遇到的问题:
我认为我使用 self.itemDataMap = rows
是错误的,如果我尝试排序,我会收到此错误消息:TypeError: list indices must be integers or slices, not tuple
。那么我如何将它与元组列表而不是字典一起使用呢?
import wx
import wx.lib.mixins.listctrl as listmix
from wx.lib.agw import ultimatelistctrl as ULC
APPNAME='Sortable Ultimate List Ctrl'
APPVERSION='1.0'
MAIN_WIDTH=300
MAIN_HEIGHT=300
class TestUltimateListCtrlPanel(wx.Panel, listmix.ColumnSorterMixin):
def __init__(self, parent):
wx.Panel.__init__(self, parent, -1, style=wx.WANTS_CHARS, size=(MAIN_WIDTH,MAIN_HEIGHT))
self.index = 0
self.list_ctrl = ULC.UltimateListCtrl(self, -1, agwStyle=ULC.ULC_REPORT|ULC.ULC_HAS_VARIABLE_ROW_HEIGHT)
self.list_ctrl.InsertColumn(0, "Make")
self.list_ctrl.InsertColumn(1, "Model")
self.list_ctrl.InsertColumn(2, "Year")
self.list_ctrl.InsertColumn(3, "Color")
rows = [("Ford", "Taurus", "1996", "Blue"),
("Nissan", "370Z", "2010", "Green"),
("Porche", "911", "2009", "Red")
]
index = 0
for data in rows:
pos=self.list_ctrl.InsertStringItem(index, data[0])
self.list_ctrl.SetStringItem(index, 1, data[1])
self.list_ctrl.SetStringItem(index, 2, data[2])
self.list_ctrl.SetStringItem(index, 3, data[3])
self.list_ctrl.SetItemData(index, rows[index])
index += 1
self.itemDataMap = rows
listmix.ColumnSorterMixin.__init__(self, 3)
self.Bind(wx.EVT_LIST_COL_CLICK, self.OnColClick, self.list_ctrl)
sizer = wx.BoxSizer(wx.VERTICAL)
sizer.Add(self.list_ctrl, 1, wx.ALL|wx.EXPAND, 5)
self.SetSizer(sizer)
def GetListCtrl(self):
return self.list_ctrl
def OnColClick(self, event):
pass
class MyForm(wx.Frame):
def __init__(self):
wx.Frame.__init__(self,None,wx.ID_ANY,'%s v%s' % (APPNAME,APPVERSION),size=(MAIN_WIDTH,MAIN_HEIGHT),style=wx.MINIMIZE_BOX | wx.SYSTEM_MENU | wx.CAPTION | wx.CLOSE_BOX | wx.CLIP_CHILDREN)
panel = TestUltimateListCtrlPanel(self)
if __name__ == "__main__":
app = wx.App(False)
frame = MyForm()
frame.Show()
app.MainLoop()
先引用一下wx.lib.mixins.listctrl.ColumnSorterMixin
的文档:
The combined class must have an attribute named itemDataMap that is a dictionary mapping the data values to a sequence of objects representing the values in each column. These values are compared in the column sorter to determine sort order.
这很难理解。
意思是,.itemDataMap
hs 是一个dictionary,其中每个条目的键是一行的数据。该值是一个列表:
self.itemDataMap = {}
for rowIndex, data in enumerate(rows):
self.itemDataMap[data] = []
immer list的每个元素都与一列相关联,用于对列的元素进行排序。如果行应该根据列的值按字母顺序排序,那么与列索引相关联的值(在行的字典中)可以是字段的值:
self.itemDataMap[data] = []
for coldata in data:
self.itemDataMap[data] += coldata
由于行已经组织在列表中,因此可以直接使用行:
self.itemDataMap[data] = data
同样可以通过
实现
self.itemDataMap = {data : data for data in rows}
注意,.itemDataMap
的键必须对应一行的数据,由SetItemData()
设置。
由于一行的数据组织在一个列表中
当列表应按特定列索引 col
的值排序时,然后列出 .itemDataMap
中与 col
关联的所有元素,并对列表进行排序通过这个元素。你可以这样想象:
col = ... # integral index of the column
sorted( [values[col] for values in self.itemDataMap.values()] )
另外注意,列数是4:
listmix.ColumnSorterMixin.__init__(self, 3)
listmix.ColumnSorterMixin.__init__(self, 4)
Class TestUltimateListCtrlPanel
:
class TestUltimateListCtrlPanel(wx.Panel, listmix.ColumnSorterMixin):
def __init__(self, parent):
wx.Panel.__init__(self, parent, -1, style=wx.WANTS_CHARS, size=(MAIN_WIDTH,MAIN_HEIGHT))
self.list_ctrl = ULC.UltimateListCtrl(self, -1, agwStyle=ULC.ULC_REPORT|ULC.ULC_HAS_VARIABLE_ROW_HEIGHT)
self.list_ctrl.InsertColumn(0, "Make")
self.list_ctrl.InsertColumn(1, "Model")
self.list_ctrl.InsertColumn(2, "Year")
self.list_ctrl.InsertColumn(3, "Color")
rows = [("Ford", "Taurus", "1996", "Blue"),
("Nissan", "370Z", "2010", "Green"),
("Porche", "911", "2009", "Red")
]
for rowIndex, data in enumerate(rows):
for colIndex, coldata in enumerate(data):
if colIndex == 0:
self.list_ctrl.InsertStringItem(rowIndex, coldata)
else:
self.list_ctrl.SetStringItem(rowIndex, colIndex, coldata)
self.list_ctrl.SetItemData(rowIndex, data)
self.itemDataMap = {data : data for data in rows}
listmix.ColumnSorterMixin.__init__(self, 4)
self.Bind(wx.EVT_LIST_COL_CLICK, self.OnColClick, self.list_ctrl)
sizer = wx.BoxSizer(wx.VERTICAL)
sizer.Add(self.list_ctrl, 1, wx.ALL|wx.EXPAND, 5)
self.SetSizer(sizer)
def GetListCtrl(self):
return self.list_ctrl
def OnColClick(self, event):
pass
我正在尝试创建一个 CheckListCtrl,您可以在其中通过单击其 header 对列中的所有数据进行排序。
在我的代码的基本示例中,我将在下面 post 设置 "rows" 作为元组列表,因为在我的最终版本中,ListCtrl 将显示 SQLite 查询的结果。
到目前为止我的代码遇到的问题:
我认为我使用 self.itemDataMap = rows
是错误的,如果我尝试排序,我会收到此错误消息:TypeError: list indices must be integers or slices, not tuple
。那么我如何将它与元组列表而不是字典一起使用呢?
import wx
import wx.lib.mixins.listctrl as listmix
from wx.lib.agw import ultimatelistctrl as ULC
APPNAME='Sortable Ultimate List Ctrl'
APPVERSION='1.0'
MAIN_WIDTH=300
MAIN_HEIGHT=300
class TestUltimateListCtrlPanel(wx.Panel, listmix.ColumnSorterMixin):
def __init__(self, parent):
wx.Panel.__init__(self, parent, -1, style=wx.WANTS_CHARS, size=(MAIN_WIDTH,MAIN_HEIGHT))
self.index = 0
self.list_ctrl = ULC.UltimateListCtrl(self, -1, agwStyle=ULC.ULC_REPORT|ULC.ULC_HAS_VARIABLE_ROW_HEIGHT)
self.list_ctrl.InsertColumn(0, "Make")
self.list_ctrl.InsertColumn(1, "Model")
self.list_ctrl.InsertColumn(2, "Year")
self.list_ctrl.InsertColumn(3, "Color")
rows = [("Ford", "Taurus", "1996", "Blue"),
("Nissan", "370Z", "2010", "Green"),
("Porche", "911", "2009", "Red")
]
index = 0
for data in rows:
pos=self.list_ctrl.InsertStringItem(index, data[0])
self.list_ctrl.SetStringItem(index, 1, data[1])
self.list_ctrl.SetStringItem(index, 2, data[2])
self.list_ctrl.SetStringItem(index, 3, data[3])
self.list_ctrl.SetItemData(index, rows[index])
index += 1
self.itemDataMap = rows
listmix.ColumnSorterMixin.__init__(self, 3)
self.Bind(wx.EVT_LIST_COL_CLICK, self.OnColClick, self.list_ctrl)
sizer = wx.BoxSizer(wx.VERTICAL)
sizer.Add(self.list_ctrl, 1, wx.ALL|wx.EXPAND, 5)
self.SetSizer(sizer)
def GetListCtrl(self):
return self.list_ctrl
def OnColClick(self, event):
pass
class MyForm(wx.Frame):
def __init__(self):
wx.Frame.__init__(self,None,wx.ID_ANY,'%s v%s' % (APPNAME,APPVERSION),size=(MAIN_WIDTH,MAIN_HEIGHT),style=wx.MINIMIZE_BOX | wx.SYSTEM_MENU | wx.CAPTION | wx.CLOSE_BOX | wx.CLIP_CHILDREN)
panel = TestUltimateListCtrlPanel(self)
if __name__ == "__main__":
app = wx.App(False)
frame = MyForm()
frame.Show()
app.MainLoop()
先引用一下wx.lib.mixins.listctrl.ColumnSorterMixin
的文档:
The combined class must have an attribute named itemDataMap that is a dictionary mapping the data values to a sequence of objects representing the values in each column. These values are compared in the column sorter to determine sort order.
这很难理解。
意思是,.itemDataMap
hs 是一个dictionary,其中每个条目的键是一行的数据。该值是一个列表:
self.itemDataMap = {}
for rowIndex, data in enumerate(rows):
self.itemDataMap[data] = []
immer list的每个元素都与一列相关联,用于对列的元素进行排序。如果行应该根据列的值按字母顺序排序,那么与列索引相关联的值(在行的字典中)可以是字段的值:
self.itemDataMap[data] = []
for coldata in data:
self.itemDataMap[data] += coldata
由于行已经组织在列表中,因此可以直接使用行:
self.itemDataMap[data] = data
同样可以通过
实现self.itemDataMap = {data : data for data in rows}
注意,.itemDataMap
的键必须对应一行的数据,由SetItemData()
设置。
由于一行的数据组织在一个列表中
当列表应按特定列索引 col
的值排序时,然后列出 .itemDataMap
中与 col
关联的所有元素,并对列表进行排序通过这个元素。你可以这样想象:
col = ... # integral index of the column
sorted( [values[col] for values in self.itemDataMap.values()] )
另外注意,列数是4:
listmix.ColumnSorterMixin.__init__(self, 3)
listmix.ColumnSorterMixin.__init__(self, 4)
Class TestUltimateListCtrlPanel
:
class TestUltimateListCtrlPanel(wx.Panel, listmix.ColumnSorterMixin):
def __init__(self, parent):
wx.Panel.__init__(self, parent, -1, style=wx.WANTS_CHARS, size=(MAIN_WIDTH,MAIN_HEIGHT))
self.list_ctrl = ULC.UltimateListCtrl(self, -1, agwStyle=ULC.ULC_REPORT|ULC.ULC_HAS_VARIABLE_ROW_HEIGHT)
self.list_ctrl.InsertColumn(0, "Make")
self.list_ctrl.InsertColumn(1, "Model")
self.list_ctrl.InsertColumn(2, "Year")
self.list_ctrl.InsertColumn(3, "Color")
rows = [("Ford", "Taurus", "1996", "Blue"),
("Nissan", "370Z", "2010", "Green"),
("Porche", "911", "2009", "Red")
]
for rowIndex, data in enumerate(rows):
for colIndex, coldata in enumerate(data):
if colIndex == 0:
self.list_ctrl.InsertStringItem(rowIndex, coldata)
else:
self.list_ctrl.SetStringItem(rowIndex, colIndex, coldata)
self.list_ctrl.SetItemData(rowIndex, data)
self.itemDataMap = {data : data for data in rows}
listmix.ColumnSorterMixin.__init__(self, 4)
self.Bind(wx.EVT_LIST_COL_CLICK, self.OnColClick, self.list_ctrl)
sizer = wx.BoxSizer(wx.VERTICAL)
sizer.Add(self.list_ctrl, 1, wx.ALL|wx.EXPAND, 5)
self.SetSizer(sizer)
def GetListCtrl(self):
return self.list_ctrl
def OnColClick(self, event):
pass