如何从TextCtrl派生wxPython自定义控件
How to derive wxPython custom control from TextCtrl
对我来说,wxPython wx.lib.masked.NumCtrl
有一些非常奇怪的怪癖。因此,我想创建我自己的 NumberCtrl
派生自 wx.TextCtrl
,它只是跳过非数字输入。旁注:缺点是 ctrl.SetValue()
只接受字符串。
下面的 class 由于在调用超级 class 构造函数时参数不匹配(或参数数量)而失败。
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()
Edit - Working code (on Linux wxpython 4.1.1)
import wx
class MyPanel(wx.Panel):
def __init__(self, parent, 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", size=(75,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, 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()
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()
对我来说,wxPython wx.lib.masked.NumCtrl
有一些非常奇怪的怪癖。因此,我想创建我自己的 NumberCtrl
派生自 wx.TextCtrl
,它只是跳过非数字输入。旁注:缺点是 ctrl.SetValue()
只接受字符串。
下面的 class 由于在调用超级 class 构造函数时参数不匹配(或参数数量)而失败。
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()
Edit - Working code (on Linux wxpython 4.1.1)
import wx
class MyPanel(wx.Panel):
def __init__(self, parent, 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", size=(75,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, 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()
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()