wx.ListCtrl: Prohibit column sorting while editing text

Hello everyone,

I am searching for a way to prohibit the ColumnSorterMixin from sorting while i am editing text. If a user clicks on a column name it will result in a sorting operation to take place but the cell which is in the editing progress will retain it’s value (see gif below). Can someone point me towards a solution?

I heard about the “event.Veto()” function. I don’t know if and how i can use it for my use case, though.
wxpython

Just skipping (or not) the event, depending on whether you are currently editing or not, should be enough.

Also, keep in mind that the SorterMixing actually sorts your data, not your view… and by just editing a label one does not change the underlying data model: so you also need to update your model by hand - otherwise, subsequent ordering operations will not work as expected.
Now, the examples in the demo are rather convoluted, and they not deal with model/view syncronization anyways. Here is a much more simple example, covering all this. I will use a TextEditMixin to allow editing, but the same applies when you just pass the LC_EDIT_LABELS style to a regular ListCtrl.

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

data = {0: 'aaa', 1: 'ddd', 2: 'ggg', 3: 'jjj', 4: 'mmm'}  # the model

class MyList(wx.ListCtrl, listmix.ColumnSorterMixin, listmix.TextEditMixin):
    def __init__(self, *a, **k):
        wx.ListCtrl.__init__(self, *a, **k)
        self.InsertColumn(0, 'some data')
        for key, val in data.items():
            index = self.InsertItem(self.GetItemCount(), val)
            self.SetItemData(index, key)
        self.itemDataMap = data
        listmix.ColumnSorterMixin.__init__(self, 1)
        listmix.TextEditMixin.__init__(self)
        self.Bind(wx.EVT_LIST_BEGIN_LABEL_EDIT, self.on_begin_edit)
        self.Bind(wx.EVT_LIST_END_LABEL_EDIT, self.on_end_edit)
        self.Bind(wx.EVT_LIST_COL_CLICK, self.on_col_click)
        self._in_edit = False

    def on_begin_edit(self, event):
        self._in_edit = True
        event.Allow()

    def on_end_edit(self, event):
        data[self.GetItemData(event.Index)] = event.GetText() # update model
        self._in_edit = False
        event.Allow()
    
    def on_col_click(self, event):
        if not self._in_edit: # skip only when not currently editing
            event.Skip()

    def GetListCtrl(self): return self
    def GetItemCount(self): return len(data)

class MainFrame(wx.Frame): 
    def __init__(self, *args, **kwargs):
        wx.Frame.__init__(self, *args, **kwargs)
        MyList(self, style=wx.LC_REPORT)

app = wx.App()
MainFrame(None).Show()
app.MainLoop()
2 Likes

Perfect, Thank you for your time !