You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何实现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自动恢复到编辑前状态,无需手动调用SetStringItem
  • event.Skip():允许事件继续执行,保存合法的数字输入

内容的提问来源于stack exchange,提问作者yam ka

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.17 08:01:30