wxPython - ListCtrl列表排序

13.4.2 如何對列表排序?

在wxPython中有三個有用的方法可以對列表進行排序,在這一節,我們將按照從易到難的順序來討論。

在創建的時候告訴列表去排序

對一個列表控件排序的最容易的方法,是在構造函數中告訴該列表控件對項目進行排序。你可以通過使用樣式標記wx.LC_SORT_ASCENDING或wx.LC_SORT_DESCENDING來實現。這兩個標記導致了列表在初始顯示的時候被排序,並且在Windows上,當新的項目被添加時,依然遵循所樣式標記來排序。對於每個列表項的數據的排序,是基於其字符串文本的,只是簡單的對字符串進行比較。如果列表是報告模式的,則排序是基於每行的最左邊的列的字符串的。

基於數據而非所顯示的文本來排序

有時,你想根據其它方面而非列表標籤的字符串來對列表排序。在wxPython中,你可以做到這一點,但這是較爲複雜的。首先,你需要爲列表中的每個項目設置項目數據,這通過使用SetItemData(item, data)方法。參數item是項目在未排序的列表中的索引,參數data必須是一個整形或長整形的值(由於C++的數據類型的限制),這就有點限制了該機制的作用。如果要獲取某行的項目數據,可以使用方法GetItemData(item)。

一旦你設置了項目數據,你就可以使用方法SortItems(func)來排序項目。參數func是一個可調用的Python對象(函數),它需要兩個整數。func函數對兩個列表項目的數據進行比較——你不能得到行自身的引用。如果第一項比第二項大的話,函數將返回一個正整數,如果第一項比第二項小的話,返回一個負值,如果相等則返回0。儘管實現這個函數的最顯而易見的方法是隻對這兩個項目做一個數字的比較就可以了,但是這並不唯一的排序方法。比如,數據項可能是外部字典或列表中的一個關鍵字,與該關鍵字相應的是一個更復雜的數據項,這種情況下,你可以通過比較與該關鍵字相應的數據項來排序。

使用mixin類進行列排序

關於對一個列表控件進行排序的常見的情況是,讓用戶能夠通過在報告模式的列表的任一列上進行敲擊來根據該列進行排序。你可以使用SortItems()機制來實現,但是它在保持到列的跟蹤方面有點複雜。幸運的是,一個名爲ColumnSorterMixin的wxPython的mixin類可以爲你處理這些信息,它位於wx.lib.mixins.listctrl模塊中。圖13.5顯示了使用該mixin類對列進行的排序。

聲明這個mixin就和Python中聲明任何其它的多重繼承一樣,如下所示:

import wx.lib.mixins.listctrl as listmix 

class ListCtrlPanel(wx.Panel, listmix.ColumnSorterMixin): 
    def __init__(self, parent, log): 
        wx.Panel.__init__(self, parent, -1, style=wx.WANTS_CHARS) 
        self.list = TestListCtrl(self, tID) 
        self.itemDataMap = musicdata 
        listmix.ColumnSorterMixin.__init__(self, 3)

例13.4是圖13.5的例子代碼

例13.4 使用mixin對一個報告列表進行排序

#!/usr/bin/python
#-*- encoding:UTF-8 -*-
import wx
import wx.lib.mixins.listctrl
import sys, glob, random
import data

class DemoFrame(wx.Frame, wx.lib.mixins.listctrl.ColumnSorterMixin):#多重繼承
    def __init__(self):
        wx.Frame.__init__(self, None, -1,
                          "wx.ListCtrl with ColumnSorterMixin",
                          size=(600,400))

        # load some images into an image list
        il = wx.ImageList(16,16, True)
        for name in glob.glob("smicon??.png"):
            bmp = wx.Bitmap(name, wx.BITMAP_TYPE_PNG)
            il_max = il.Add(bmp)

        # add some arrows for the column sorter
    # 添加箭頭到圖像列表
        self.up = il.AddWithColourMask(
            wx.Bitmap("sm_up.bmp", wx.BITMAP_TYPE_BMP), "blue")
        self.dn = il.AddWithColourMask(
            wx.Bitmap("sm_down.bmp", wx.BITMAP_TYPE_BMP), "blue")
        
        # create the list control
        self.list = wx.ListCtrl(self, -1, style=wx.LC_REPORT)

        # assign the image list to it
        self.list.AssignImageList(il, wx.IMAGE_LIST_SMALL)

        # Add some columns
        for col, text in enumerate(data.columns):
            self.list.InsertColumn(col, text)

        # add the rows
    # 創建數據映射
        self.itemDataMap = {}
        for item in data.rows:
            index = self.list.InsertStringItem(sys.maxint, item[0])
            for col, text in enumerate(item[1:]):
                self.list.SetStringItem(index, col+1, text)

            # give each item a data value, and map it back to the
            # item values, for the column sorter
            self.list.SetItemData(index, index)# 關聯數據和映射
            self.itemDataMap[index] = item
            
            # give each item a random image
            img = random.randint(0, il_max)
            self.list.SetItemImage(index, img, img)
                
        # set the width of the columns in various ways
        self.list.SetColumnWidth(0, 120)
        self.list.SetColumnWidth(1, wx.LIST_AUTOSIZE)
        self.list.SetColumnWidth(2, wx.LIST_AUTOSIZE)
        self.list.SetColumnWidth(3, wx.LIST_AUTOSIZE_USEHEADER)

        # initialize the column sorter
        wx.lib.mixins.listctrl.ColumnSorterMixin.__init__(self,
                                                          len(data.columns))

    def GetListCtrl(self):
        return self.list

    def GetSortImages(self):
        return (self.dn, self.up)


app = wx.PySimpleApp()
frame = DemoFrame()
frame.Show()
app.MainLoop()

爲了使用該mixin工作,你需要執行下面的東西:

1、擴展自ColumnSorterMixin的類(這裏是DemoFrame)必須有一個名爲GetListCtrl()的方法,它返回實際要被排序的列表控件。該方法被這個mixin用來得到控件的一個索引。

2、在擴展自ColumnSorterMixin的類(這裏是DemoFrame)的__init__()方法中,在你調用ColumnSorterMixin的__init__()方法之前,你必須創建GetListCtrl()所要引用的列表控件。該mixin的__init__()方法要求一個代表列表控件中的列號的整數值。

3、你必須使用SetItemData()爲列表中的每行設置一個唯一的數據值。

4、擴展自ColumnSorterMixin的類(這裏是DemoFrame)必須有一個名爲itemDataMap的屬性。該屬性必須是一個字典。字典中的關鍵性的東西是由SetItemData()設置的數據值。這些值是你想用來對每列進行排序的值的一個元組。(典型情況下,這些值將是每列中的文本)。按句話說,itemDataMap本質上是將控件中的數據複製成另一種易於排序的形式。

在ColumnSorterMixin的通常用法中,你要麼創建itemDataMap用來添加項目到你的列表控件,要麼你首先創建itemDataMap,並用它來建造列表控件本身。

儘管配置可能有點複雜,但ColumnSorterMixin對於列的排序是一個不錯的選擇。



轉載請註明文章來源:www.pythontik.com
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章