【问题标题】:wxPython - How to sort ListCtrl column items?wxPython - 如何对 ListCtrl 列项目进行排序?
【发布时间】:2019-06-20 13:32:29
【问题描述】:

我正在尝试创建一个 CheckListCtrl,您可以通过单击其标题对列中的所有数据进行排序。

在我的代码的基本示例中,我将在下面发布我将“行”设置为元组列表,因为在我的最终版本中,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()

【问题讨论】:

    标签: python python-3.x user-interface wxpython


    【解决方案1】:

    首先我引用wx.lib.mixins.listctrl.ColumnSorterMixin的文档:

    组合类必须有一个名为 itemDataMap 的属性,它是一个字典,将数据值映射到表示每列中的值的对象序列。这些值在列排序器中进行比较以确定排序顺序。

    这很难理解。

    这意味着.itemDataMapdictionary,其中每个条目的键是一行的数据。该值是一个列表:

    self.itemDataMap = {}
    for rowIndex, data in enumerate(rows):
        self.itemDataMap[data] = []
    

    immer 列表的每个元素都与一列相关联,用于对列的元素进行排序。如果行应根据列的值按字母顺序排序,则与列索引关联的值(在行的字典中)可以是字段的值:

    self.itemDataMap[data] = []
    for coldata in data:
        self.itemDataMap[data] += coldata
    

    由于行已经组织在一个列表中,可以直接使用行:

    self.itemDataMap[data] = data
    

    同样可以通过

    实现
    self.itemDataMap = {data : data for data in rows} 
    

    注意,.itemDataMap的keys必须对应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)


    班级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
    

    【讨论】:

    • 非常感谢您对新人友好的回答!我知道解决方案并了解它的工作原理。完美!
    猜你喜欢
    • 2013-08-06
    • 2017-01-13
    • 2011-02-09
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-06-08
    相关资源
    最近更新 更多