An editable listctrl performs well in all but one circumstances: when no row is selected – as immediately when the list shows up or by clicking on empty space, by single clicking on any cell on first row, that cell enters directly in edit mode. On the other hand, by single clicking on any other row (also when none is prior selected), that row is first selected and only at the next single click the respective cell enters in edit mode.
Here is a test code:
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
import wx
import wx.lib.mixins.listctrl as listmix
##
class EditableListCtrl(wx.ListCtrl, listmix.TextEditMixin):
def __init__(self, parent, ID = wx.ID_ANY, pos = wx.DefaultPosition, size = wx.DefaultSize, style = 0):
wx.ListCtrl.__init__(self, parent, ID, pos, size, style)
listmix.TextEditMixin.__init__(self)
##
class MyPanel(wx.Panel):
def __init__(self, parent):
wx.Panel.__init__(self, parent)
some_data = [("abc", "def", "ghi"), ("jkl", "mno", "pqr")]
self.list_ctrl = EditableListCtrl(self, wx.ID_ANY, style = wx.LC_REPORT | wx.LC_HRULES)
self.list_ctrl.InsertColumn(0, "col_1")
self.list_ctrl.InsertColumn(1, "col_2")
self.list_ctrl.InsertColumn(2, "col_3")
index = 0
for row in some_data:
self.list_ctrl.InsertItem(index, row[0])
self.list_ctrl.SetItem(index, 1, row[1])
self.list_ctrl.SetItem(index, 2, row[2])
index += 1
sizer = wx.BoxSizer(wx.VERTICAL)
sizer.Add(self.list_ctrl, 0, wx.ALL|wx.EXPAND, 5)
self.SetSizer(sizer)
self.list_ctrl.Bind(wx.EVT_LIST_ITEM_SELECTED, self.OnListItemSelected)
##
def OnListItemSelected(self, event):
event.Skip()
##
class MyFrame(wx.Frame):
def __init__(self):
wx.Frame.__init__(self, None, wx.ID_ANY, "Editable List Control")
panel = MyPanel(self)
self.Show()
##
if __name__ == "__main__":
app = wx.App(False)
frame = MyFrame()
app.MainLoop()
Because that ‘feature’ continued to annoy the hell out of me [*], I digged into the listctrl code and came up with a workaround, that – at least for me – it simply works: by changing value 0
to -2
in line 476 of the code (under class TextEditMixin
), all listctrl lines now behave the same, whether it’s about the first or the tenth row. More specifically:
# value of old line 476:
self.curRow = 0
# value of new line 476:
self.curRow = -2
As far as I understand, a negative value is required by OnLeftDown
call in order to differentiate from clicking on empty space versus over a line (I inserted a print (row)
at line 539 to observe that) and because -1 is already used as flag for other part of listctrl program, I just used -2 as my own flag.
Also there there is a self.curCol = 0
, but the columns didn’t bother me, so I didn’t touch that one
The particular implementation of listctrl in my program is a bit more complex than just enable editing (involves sorting, some line manipulation etc.) and until now everything seems to work fine.
So, question: could this be a permanent fix ? What undesired side effect may occur ?
In my case, I used the modified listctrl.py file as if it were my own custom module, i.e. I put it together with my other own modules that are part of my main program; that way, the workaround is ported to whatever PC my program is running.
Cristi
[*] I also tried switching to ultimatelistctrl alternative and then to a patched-for-python3 ObjectListView version (further patched by myself in order to solve some runtime errors), but I didn’t liked various things there, so I came back to listctrl.