简体   繁体   中英

Overwritten TreeCtrl.OnCompareItems() not called in Python 3 - wxPython 4

I have a wx.TreeCtrl structure where the user can sort the items by different criteria (date, name, id, descending, ascending, ...). This worked fine in Python 2, but Python 3 (with wxPython 4) refuses sorting. The method CTreeCtrl.OnCompareItems() is called in Python 2, but never in Python 3.

In the functools.cmp_to_key documentation ( https://docs.python.org/3/library/functools.html ) I found a hint: Python 3 does not support comparison functions. Confusing: in the description of wx.TreeCtrl (wxPython 4) there is a comparison method OnCompareItems() ( https://docs.wxpython.org/wx.TreeCtrl.html#wx.TreeCtrl.OnCompareItems ). The description says, that together with this method I must use the RTTI macros DECLARE_DYNAMIC_CLASS and IMPLEMENT_DYNAMIC_CLASS since the baseclass does not know that I overwrote OnCompareItems() . I found only descriptions of how to use this macros in C++, but nothing for python.

I have no idea how I could make my program calling my OnCompareItems() method in Python3/wxPython 4.

Can anybody help?

Regards, Humbalan

Below there is a small sample programm which reflects the problem. It runs with Python 2 and Python 3 as well. The print( 'in CTreeCtrl.OnCompareItems()' ) shows, that this method is called (in py2) or not called (in py3):

import sys
import wx

class CTreeCtrl( wx.TreeCtrl ):
    def __init__( self, parent ):
        super( CTreeCtrl, self ).__init__( parent=parent, style=wx.TR_HIDE_ROOT )

    def OnCompareItems( self, item1, item2 ):
        print( 'in CTreeCtrl.OnCompareItems()' )
        if sys.version_info.major < 3:
            d1 = self.GetItemData( item1 ).Data
            d2 = self.GetItemData( item2 ).Data
        else:
            d1 = self.GetItemData( item1 )
            d2 = self.GetItemData( item2 )

        if   d1 < d2:  return -1
        elif d1 > d2:  return 1
        else        :  return 0


class CSettingsTree( wx.Dialog  ):

    def __init__( self, parent, settings ) :

        size = wx.Size(200,150)

        wx.Dialog.__init__( self, parent, title='all settings', size=size )
        bSizer_main = wx.BoxSizer( wx.VERTICAL )

        self.m_treeCtrl = CTreeCtrl( self  )
        bSizer_main.Add( self.m_treeCtrl, 0, wx.ALL|wx.EXPAND, 5 )

        self.SetSizer( bSizer_main )
        bSizer_main.Fit( self )

        root = self.m_treeCtrl.AddRoot( 'Settings' )

        for key, name in settings :
            if sys.version_info.major < 3 :  sort_key = wx.TreeItemData( name )
            else                          :  sort_key = name

            self.m_treeCtrl.AppendItem( root, '{}: {}'.format(key, name), data=sort_key )

        self.m_treeCtrl.ExpandAll()
        self.m_treeCtrl.SortChildren( root )



#---------------------------------------------------------------------------
if __name__=="__main__":

    app = wx.App( redirect=False )

    settings = [(50,'Taylor'),(200,'Mueller'),(101,'Baker'),(102,'Smith')]

    dlg = CSettingsTree( wx.Frame( None ), settings )
    dlg.ShowModal()

Edit (2018-03-08, 2:52pm)

It seems that this is a bug in the c++ part of wxPython (see https://github.com/wxWidgets/Phoenix/issues/774 ) and the fix is still not available.

I had the same problem when attempting to sort customtreectrl items according to an arbitrary field, rather than only alphabetically as originally implemented. I don't want to duplicate the comments above, except to say a fix now exists ( here , as given in @Humbalan's edit to their own question).

It's probably not worth providing a full example, as @Humbalan's question has plenty of detail, but in my case I create the tree items with something like this:

ctc_item = self.tree_ctc.AppendItem(ctc_parent, text = ctc_text, data = {'id_': ctc_id})

where self.tree_ctc = MyCustomTreeCtrl(self, style = some_style) . My tree control and (overridden) OnCompareItems() method are:

class MyCustomTreeCtrl(ctc.CustomTreeCtrl):

    def __init__(self, parent, style):
        ctc.CustomTreeCtrl.__init__(self, parent, agwStyle = style)

    def OnCompareItems(self, item1, item2):
        t1 = self.GetPyData(item1)['id_']
        t2 = self.GetPyData(item2)['id_']

        if t1 < t2:  return -1
        if t1 == t2: return 0
        return 1

I realise the question is a couple of years old, but this is hopefully useful.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM