微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

如何从TextCtrl派生wxPython自定义控件

如何解决如何从TextCtrl派生wxPython自定义控件

对我来说,wxPython wx.lib.masked.NumCtrl 有一些非常奇怪的怪癖。因此,我想创建自己的 NumberCtrl 派生自 wx.TextCtrl,它只是跳过非数字输入。旁注:缺点是 ctrl.SetValue() 只接受字符串。

由于调用超类构造函数中的参数(或参数数量)不匹配,以下类失败。

class NumberCtrl(wx.TextCtrl):

    def __init__(self,parent,id=wx.ID_ANY,label=None):
        wx.TextCtrl.__init__(self,parent=parent,id=id,label=label)
        self.Bind(wx.EVT_CHAR,lambda event: self.force_numeric(event))

    def force_numeric(self,event):
        raw_value = self.GetValue().strip()
        keycode = event.GetKeyCode()
        if keycode < 255:
            if chr(keycode).isdigit() or chr(keycode) == '.' and '.' not in raw_value:
                event.Skip()

但是,仅使用基本参数是可行的。

def __init__(self,parent):
    wx.TextCtrl.__init__(self,parent=parent)

我不明白这里发生了什么。

解决方法

尝试简单地使用 TextCtrl 的显式初始化值。

我已将 label 替换为 value,并在事件验证中添加了允许“退格”(我的设置中的键码 8)。

编辑将 value 的默认值更改为字符串 not None

class NumberCtrl(wx.TextCtrl):

    def __init__(self,parent,id=wx.ID_ANY,value="",pos=wx.DefaultPosition,size=wx.DefaultSize,style=0,validator=wx.DefaultValidator,name=wx.TextCtrlNameStr):
        wx.TextCtrl.__init__(self,parent=parent,id=id,value=value)
        self.Bind(wx.EVT_CHAR,lambda event: self.force_numeric(event))

    def force_numeric(self,event):
        raw_value = self.GetValue().strip()
        keycode = event.GetKeyCode()
        print(keycode) 
        if keycode < 255:
            if chr(keycode).isdigit() or keycode == 8 or chr(keycode) == '.' and '.' not in raw_value:
                event.Skip()

编辑 - 工作代码(在 Linux wxpython 4.1.1 上)

import wx

class MyPanel(wx.Panel):

    def __init__(self,flags=0):
        super().__init__(parent)

        # Panel 1 (contains button that takes up entire panel)
        self.pnl1 = wx.Panel(self)
        self.btn1 = wx.Button(self.pnl1,label="Panel2",size=(250,75))
        self.btn1.Bind(wx.EVT_BUTTON,self.show_pnl2)

        vbox1 = wx.BoxSizer(wx.VERTICAL)
        vbox1.Add(self.btn1)
        self.pnl1.SetSizer(vbox1)

        # Panel 2 (contains button that takes up entire panel)
        self.pnl2 = wx.Panel(self)
        self.btn2 = wx.Button(self.pnl2,label="Panel1",size=(75,250))
        self.num = NumberCtrl(self.pnl2,wx.ID_ANY,value="1",250))
        self.btn2.Bind(wx.EVT_BUTTON,self.show_pnl1)

        vbox2 = wx.BoxSizer(wx.VERTICAL)
        vbox2.Add(self.btn2)
        vbox2.Add(self.num)
        self.pnl2.SetSizer(vbox2)

        # Main panel (displays either Panel 1 or Panel 2)
        vbox = wx.BoxSizer(wx.VERTICAL)
        vbox.Add(self.pnl1,flag=flags)
        vbox.Add(self.pnl2,flag=flags)
        self.SetSizer(vbox)

        # Start off with panel 1 showing and panel 2 hidden
        self.Show()
        self.pnl1.Hide()

    def show_pnl1(self,event):
        self.pnl2.Hide()
        self.pnl1.Show()
        self.Layout()
        self.Fit()

    def show_pnl2(self,event):
        self.pnl1.Hide()
        self.pnl2.Show()
        self.Layout()
        self.Fit()

class NumberCtrl(wx.TextCtrl):

    def __init__(self,event):
        raw_value = self.GetValue().strip()
        keycode = event.GetKeyCode()
        print(keycode) 
        if keycode < 255:
            if chr(keycode).isdigit() or keycode == 8 or chr(keycode) == '.' and '.' not in raw_value:
                event.Skip()

class PanelSwitchExample(wx.Frame):
    """Represents application window that includes switchable panel"""

    def __init__(self,flags=0):
        super().__init__(None)

        vbox = wx.BoxSizer(wx.VERTICAL)
        vbox.Add(MyPanel(self,flags))
        self.SetSizer(vbox)
        self.Show()

if __name__ == "__main__":
    app = wx.App()

    PanelSwitchExample()
    app.MainLoop()

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。