I want to make editable ListCtrl which accept only numbers from user . I have this code :
import wx
import wx.lib.mixins.listctrl as listmix
class EditableListCtrl(wx.ListCtrl, listmix.TextEditMixin):
''' TextEditMixin allows any column to be edited. '''
#----------------------------------------------------------------------
def __init__(self, parent, ID=wx.ID_ANY, pos=wx.DefaultPosition,
size=wx.DefaultSize, style=0):
"""Constructor"""
wx.ListCtrl.__init__(self, parent, ID, pos, size, style)
listmix.TextEditMixin.__init__(self)
def OpenEditor(self, col, row):
# '''Enable the editor for the column 2(year)'''
if col == 2 :
self._editing = (col, row)
listmix.TextEditMixin.OpenEditor(self, col, row)
########################################################################
class MyPanel(wx.Panel):
""""""
#----------------------------------------------------------------------
def __init__(self, parent):
"""Constructor"""
wx.Panel.__init__(self, parent)
rows = [("Ford", "Taurus", "1996", "Blue"),
("Nissan", "370Z", "2010", "Green"),
("Porche", "911", "2009", "Red")
]
self.list_ctrl = EditableListCtrl(self, style=wx.LC_REPORT)
self.list_ctrl.InsertColumn(0, "Make")
self.list_ctrl.InsertColumn(1, "Model")
self.list_ctrl.InsertColumn(2, "Year")
self.list_ctrl.InsertColumn(3, "Color")
index = 0
for row in rows:
self.list_ctrl.InsertStringItem(index, row[0])
self.list_ctrl.SetStringItem(index, 1, row[1])
self.list_ctrl.SetStringItem(index, 2, row[2])
self.list_ctrl.SetStringItem(index, 3, row[3])
index += 1
self.list_ctrl.Bind(wx.EVT_LIST_END_LABEL_EDIT, self.OnUpdate)
sizer = wx.BoxSizer(wx.VERTICAL)
sizer.Add(self.list_ctrl, 0, wx.ALL|wx.EXPAND, 5)
self.SetSizer(sizer)
def OnUpdate(self, event):
row_id = event.GetIndex() #Get the current row
col_id = event.GetColumn () #Get the current column
new_data = event.GetLabel() #Get the changed data
item = self.list_ctrl.GetItem(row_id, col_id)
OldData= item .GetText()
try :
new_data_int = int(new_data)#check if user enter number or not
except: #if not , add the old data again
self.list_ctrl.SetStringItem(row_id,col_id,OldData)
########################################################################
class MyFrame(wx.Frame):
""""""
#----------------------------------------------------------------------
def __init__(self):
"""Constructor"""
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()
But when I try to add the old data again :
self.list_ctrl.SetStringItem(row_id,col_id,OldData)
ListCtrl save the change from user (ListCtrl does not add the old data) , what can I do to make ListCtrl add the old data OR is there another way to Make wxPython editable ListCtrl accept only numbers from user?
Edit : I used Veto() And It is worked Thank you for your nice answers.
My code became Like this :
import wx
import wx.lib.mixins.listctrl as listmix
class EditableListCtrl(wx.ListCtrl, listmix.TextEditMixin):
''' TextEditMixin allows any column to be edited. '''
#----------------------------------------------------------------------
def __init__(self, parent, ID=wx.ID_ANY, pos=wx.DefaultPosition,
size=wx.DefaultSize, style=0):
"""Constructor"""
wx.ListCtrl.__init__(self, parent, ID, pos, size, style)
listmix.TextEditMixin.__init__(self)
def OpenEditor(self, col, row):
# '''Enable the editor for the column 2(year)'''
if col == 2 :
self._editing = (col, row)
listmix.TextEditMixin.OpenEditor(self, col, row)
########################################################################
class MyPanel(wx.Panel):
""""""
#----------------------------------------------------------------------
def __init__(self, parent):
"""Constructor"""
wx.Panel.__init__(self, parent)
rows = [("Ford", "Taurus", "1996", "Blue"),
("Nissan", "370Z", "2010", "Green"),
("Porche", "911", "2009", "Red")
]
self.list_ctrl = EditableListCtrl(self, style=wx.LC_REPORT)
self.list_ctrl.InsertColumn(0, "Make")
self.list_ctrl.InsertColumn(1, "Model")
self.list_ctrl.InsertColumn(2, "Year")
self.list_ctrl.InsertColumn(3, "Color")
index = 0
for row in rows:
self.list_ctrl.InsertStringItem(index, row[0])
self.list_ctrl.SetStringItem(index, 1, row[1])
self.list_ctrl.SetStringItem(index, 2, row[2])
self.list_ctrl.SetStringItem(index, 3, row[3])
index += 1
self.list_ctrl.Bind(wx.EVT_LIST_END_LABEL_EDIT, self.OnUpdate)
sizer = wx.BoxSizer(wx.VERTICAL)
sizer.Add(self.list_ctrl, 0, wx.ALL|wx.EXPAND, 5)
self.SetSizer(sizer)
def OnUpdate(self, event):
row_id = event.GetIndex() #Get the current row
col_id = event.GetColumn () #Get the current column
new_data = event.GetLabel() #Get the changed data
try :
new_data_int = int(new_data)#check if user enter number or not
event.Skip()
except: #if not , Kill The Edit Event
event.Veto()
########################################################################
class MyFrame(wx.Frame):
""""""
#----------------------------------------------------------------------
def __init__(self):
"""Constructor"""
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()



You can make use of the
CloseEditorfunction in the mixin to check for validity.Although this version is simplistic and only works for the one item. You'd have to do some work if you wanted to extend it.
Edited to simplify the code, where I got confused by the fact that
CloseEditorgets called twice, once for the control and again for a Focus event, which could result in non-numeric data still be written.