pythonsortingwxpythonlistctrl

wxPython - How to get what data checked after sorting (listmix.ColumnSorterMixin)


I have a data in dictionary which will go to ListCtrl. I have checkboxes listmix.CheckListCtrlMixin for selecting data and listmix.ColumnSorterMixin for sorting.

The problem is that after I sorted data by any column the original order of data is changed and after checking items I can't find the data for further action.

Is it possible to get new "after sorting" dict or something like that?

Here's the demo example.

import sys
import wx
import  wx.lib.mixins.listctrl  as  listmix

musicdata = {
1  : ( 'Bad English', 'The Price Of Love', 'Rock' ),
2  : ( 'Michael Bolton', 'How Am I Supposed To Live Without You', 'Blues' ),
3  : ( 'Paul Young', 'Oh Girl', 'Rock' ),
4  : ( 'Paula Abdul', 'Opposites Attract', 'Rock' ),
5  : ( 'Richard Marx', 'Should\'ve Known Better', 'Rock' ),
6 : ( 'Rod Stewart', 'Forever Young', 'Rock' ),
7 : ( 'Roxette', 'Dangerous', 'Rock' ),
}

class TestListCtrl( wx.ListCtrl, listmix.ListCtrlAutoWidthMixin, listmix.CheckListCtrlMixin ) :

    def __init__( self, parent, ID, pos=wx.DefaultPosition,
              size=wx.DefaultSize, style=0 ) :

        wx.ListCtrl.__init__( self, parent, ID, pos, size, style )

        listmix.ListCtrlAutoWidthMixin.__init__( self )
        listmix.CheckListCtrlMixin.__init__(self)
        self.Bind(wx.EVT_LIST_COL_CLICK, self.OnCheckItem)


    def OnCheckItem(self, data, flag):
        print(data, flag)

class TabPanel( wx.Panel, listmix.ColumnSorterMixin ) :

    def __init__( self, parent  ) :

        wx.Panel.__init__( self, parent=parent, id=wx.ID_ANY )

        self.createAndLayout()

    def createAndLayout( self ) :

        sizer = wx.BoxSizer( wx.VERTICAL )
        self.list = TestListCtrl( self, wx.ID_ANY, style=wx.LC_REPORT
                             | wx.BORDER_NONE
                             | wx.LC_EDIT_LABELS
                             | wx.LC_SORT_ASCENDING )

        sizer.Add( self.list, 1, wx.EXPAND )
        self.populateList()

        self.itemDataMap = musicdata
        listmix.ColumnSorterMixin.__init__( self, 3 )
        self.SetSizer( sizer )
        self.SetAutoLayout( True )

    def populateList( self ) :

        self.list.InsertColumn( 0, 'Artist' )
        self.list.InsertColumn( 1, 'Title', wx.LIST_FORMAT_RIGHT )
        self.list.InsertColumn( 2, 'Genre' )
        items = musicdata.items()

        for key, data in items :
            index = self.list.InsertStringItem( sys.maxint, data[ 0 ] )
            self.list.SetStringItem( index, 1, data[ 1 ] )
            self.list.SetStringItem( index, 2, data[ 2 ] )
            self.list.SetItemData( index, key )

        self.list.SetColumnWidth( 0, wx.LIST_AUTOSIZE )
        self.list.SetColumnWidth( 1, wx.LIST_AUTOSIZE )
        self.list.SetColumnWidth( 2, 100 )

        self.list.SetItemState( 5, wx.LIST_STATE_SELECTED, wx.LIST_STATE_SELECTED )

        self.currentItem = 0

    def GetListCtrl( self ) :
        return self.list

class DemoFrame( wx.Frame ) :

     def __init__( self ) :

        wx.Frame.__init__( self, None, wx.ID_ANY, title="Panel Tutorial",
                           size=(600, 300) )

        panel = TabPanel( self )
        self.Show()

app = wx.App()
frame = DemoFrame()
app.MainLoop()

Solution

  • As the answer to this question :Sort a Python dictionary by value shows, it is not possible to sort a dict, only to get a representation of a dict that is sorted.

    You can obtain the list of items in a sorted order after clicking on one of the column headers by defining a function in class TestListCtrl like this:

    class TestListCtrl( wx.ListCtrl, listmix.ListCtrlAutoWidthMixin, listmix.CheckListCtrlMixin ) :
    
        def __init__( self, parent, ID, pos=wx.DefaultPosition,
                  size=wx.DefaultSize, style=0 ) :
    
            wx.ListCtrl.__init__( self, parent, ID, pos, size, style )
    
            listmix.ListCtrlAutoWidthMixin.__init__( self )
            listmix.CheckListCtrlMixin.__init__(self)
            self.Bind(wx.EVT_LIST_COL_CLICK, self.OnCheckItem)
            self.Binf(wx.EVT_LIST_COL_CLICK, self.GetSortedOrder)
    
    
        def OnCheckItem(self, data, flag):
            print(data, flag)
    
        def GetSortedOrder(self, event):
            count = self.GetItemCount()
            self.sorted_artists = [self.GetItem(itemId=row, col=0).GetText() for row in xrange(count)]
            print self.sorted_artists
    

    The method GetSortedOrder() will create a sorted_artists attribute which is a list of the artists in the sorted order updated every time you click any of the column headers. You can get other values such as Title or Genre by changing the name of the column. Use this to compare against the original dict and create a new dict if you want