wxPython 对话框:如何验证多个控件中的输入?



我有一个包含多个输入字段的wx.Dialog。按下"确定"按钮时,我想运行验证,例如:

  • 如果填写了三个字段中的一个,则必须填写所有三个字段。
  • 如果设置了单选按钮,则其对应的字段不得为空。

我知道普通的验证器会附加到带有wx.Window.SetValidator()的控件。但这些只是验证其各自控件的内容。

我尝试将验证器附加到wx.Dialog,但不幸的是,这没有被调用。

我尝试将事件从ID_OK按钮绑定到处理程序以在那里进行验证,但结果是对话框不再关闭。

进行这种验证的正确方法是什么?

以下是我尝试过的代码:

import wx

class DialogValidator(wx.Validator):
def Clone(self):
return DialogValidator()
def Validate(self, win):
print("this method is never called :-(")
field1 = win.field1.GetValue()
field2 = win.field2.GetValue()
field3 = win.field3.GetValue()
if len(field1) > 0 or len(field2) > 0 or len(field3) > 0:
# if one of these is filled in, all three must
if len(field1) == 0 or len(field2) == 0 or len(field3) == 0:
wx.MessageBox("All three fields must be filled in!", "Error")
return False
return True
def TransferToWindow(self):
return True
def TransferFromWindow(self):
return True

class MyDialog(wx.Dialog):
def __init__(self, *args, **kwds):
wx.Dialog.__init__(self, *args, **kwds)
self.field1 = wx.TextCtrl(self, wx.ID_ANY, "")
self.field2 = wx.TextCtrl(self, wx.ID_ANY, "")
self.field3 = wx.TextCtrl(self, wx.ID_ANY, "")
self.radio1 = wx.RadioButton(self, wx.ID_ANY, "radio1", style=wx.RB_GROUP)
self.radio2 = wx.RadioButton(self, wx.ID_ANY, "radio2")
self.dialog_btn_sizer = wx.StdDialogButtonSizer()
self.dialog_btn_sizer.AddButton(wx.Button(self, wx.ID_OK))
self.dialog_btn_sizer.AddButton(wx.Button(self, wx.ID_CANCEL))
self.dialog_btn_sizer.Realize()
main_sizer = wx.BoxSizer(wx.VERTICAL)
main_sizer.Add(self.radio1)
main_sizer.Add(self.radio2)
main_sizer.Add(self.field1)
main_sizer.Add(self.field2)
main_sizer.Add(self.field3)
main_sizer.Add(self.dialog_btn_sizer, 0, wx.EXPAND, 0)
self.SetSizer(main_sizer)
main_sizer.Fit(self)
self.Layout()
self.SetValidator(DialogValidator())  # doesn't work unfortunately
self.Bind(wx.EVT_BUTTON, self.on_ok, id=wx.ID_OK)  # doesn't work either
def on_ok(self, event):
field1 = self.field1.GetValue()
field2 = self.field2.GetValue()
field3 = self.field3.GetValue()
if len(field1) > 0 or len(field2) > 0 or len(field3) > 0:
# if one of these is filled in, all three must
if len(field1) == 0 or len(field2) == 0 or len(field3) == 0:
wx.MessageBox("All three fields must be filled in!", "Error")
event.Skip()
return
# Note that I do NOT call event.Skip() here!
# I was hoping the original handler would pick up the event
#   and properly close the dialog -> unfortunately this is not the case
print("inputs fine, now the dialog should get closed")

我现在通过在通过对话框访问其他字段的一个字段上设置验证器来解决它。我发现wx.Validator.Validate(self, win)的胜利是指潜在的wx.Dialog

(我不知道为什么处理ID_OK按钮不起作用,但这将是另一个问题。

我发布我的解决方案,希望它能帮助其他与验证器作斗争的人:

import wx

class FieldValidator(wx.Validator):
def Clone(self):
return FieldValidator()
def Validate(self, win):
# 'win' refers to the dialog,
# so I can access the other controls like this:
field1 = win.field1.GetValue()
field2 = win.field2.GetValue()
field3 = win.field3.GetValue()
# btw: with self.GetWindow() I can get the control being validated
if len(field1) > 0 or len(field2) > 0 or len(field3) > 0:
# if one of these is filled in, all three must
if len(field1) == 0 or len(field2) == 0 or len(field3) == 0:
wx.MessageBox("All three fields must be filled in!", "Error")
return False
return True
def TransferToWindow(self):
return True
def TransferFromWindow(self):
return True

class MyDialog(wx.Dialog):
def __init__(self, *args, **kwds):
wx.Dialog.__init__(self, *args, **kwds)
self.field1 = wx.TextCtrl(self, wx.ID_ANY, "")
self.field2 = wx.TextCtrl(self, wx.ID_ANY, "")
self.field3 = wx.TextCtrl(self, wx.ID_ANY, "")
self.radio1 = wx.RadioButton(self, wx.ID_ANY, "radio1", style=wx.RB_GROUP)
self.radio2 = wx.RadioButton(self, wx.ID_ANY, "radio2")
self.dialog_btn_sizer = wx.StdDialogButtonSizer()
self.dialog_btn_sizer.AddButton(wx.Button(self, wx.ID_OK))
self.dialog_btn_sizer.AddButton(wx.Button(self, wx.ID_CANCEL))
self.dialog_btn_sizer.Realize()
main_sizer = wx.BoxSizer(wx.VERTICAL)
main_sizer.Add(self.radio1)
main_sizer.Add(self.radio2)
main_sizer.Add(self.field1)
main_sizer.Add(self.field2)
main_sizer.Add(self.field3)
main_sizer.Add(self.dialog_btn_sizer, 0, wx.EXPAND, 0)
self.SetSizer(main_sizer)
main_sizer.Fit(self)
self.Layout()
self.field1.SetValidator(FieldValidator())

最新更新