如何实现wxPython可编辑ListCtrl仅接受数字输入?
问题:实现仅接受数字输入的wxPython可编辑ListCtrl
问题描述
我想实现一个仅接受用户输入数字的wxPython可编辑ListCtrl,编写了初始代码,但尝试用self.list_ctrl.SetStringItem(row_id,col_id,OldData)恢复旧数据时,ListCtrl仍会保存非法输入,请问如何让ListCtrl恢复旧数据,或者有其他方法实现仅接受数字输入的可编辑ListCtrl?
初始代码
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 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()
问题原因
直接调用SetStringItem恢复旧数据无法生效,是因为wx.EVT_LIST_END_LABEL_EDIT事件默认会提交用户的输入,即使后续修改控件内容,事件的默认处理逻辑已经完成了输入保存。
解决方案:使用event.Veto()阻止非法输入提交
通过调用event.Veto()可以直接否决本次编辑事件,让ListCtrl自动保留原数据;合法输入则调用event.Skip()允许事件继续处理。修正后的代码如下:
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 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()
说明
event.Veto():取消本次编辑操作,ListCtrl自动恢复到编辑前状态,无需手动调用SetStringItemevent.Skip():允许事件继续执行,保存合法的数字输入
内容的提问来源于stack exchange,提问作者yam ka
相关产品推荐
相关产品推荐

