wxPython,单选按钮选择/取消选择和wx.RB_GROUP

时间:2013-02-13 22:19:26

标签: wxpython radio-button

wxPython和(分组)单选按钮问题:

我有三个单独绑定的单选按钮,我看到这给了我一个单选按钮A,B或C的选择,其中一个总是被选中 - 我很欣赏这是wx.RB_GROUP的本质样式;

是否可以通过单击单选按钮取消选择所有按钮,如A = B = C = False?我已经简化了代码(下面),其中重置按钮执行此功能,但理想情况下我只想在GUI中取消选择。

import wx
class MyForm(wx.Frame):
    def __init__(self):
        wx.Frame.__init__(self, None, -1, "Tutorial", size=(300,250))
        panel = wx.Panel(self, wx.ID_ANY)
        self.radio1 = wx.RadioButton(panel, label="A", pos=(20,40), style=wx.RB_GROUP)
        self.radio2 = wx.RadioButton(panel, label="B", pos=(20,70))
        self.radio3 = wx.RadioButton(panel, label="C", pos=(20,100))

        btn = wx.Button(panel, label="Check", pos=(20,140))
        rst = wx.Button(panel, label="Reset", pos=(20,170))
        btn.Bind(wx.EVT_BUTTON, self.onBtn)
        rst.Bind(wx.EVT_BUTTON, self.onRst)

    def onBtn(self, event):
        print "A = ", self.radio1.GetValue()
        print "B = ", self.radio2.GetValue()
        print "C = ", self.radio3.GetValue()
        print "\n\n"

    def onRst(self, event):
        self.radio1.SetValue( 0 )
        self.radio2.SetValue( 0 )
        self.radio3.SetValue( 0 )

if __name__ == "__main__":
    app = wx.PySimpleApp()
    frame = MyForm().Show()
    app.MainLoop()

2 个答案:

答案 0 :(得分:4)

据我所知,wxPython本身不支持。此外,这不是任何UI中单选按钮的预期行为,因此我首先想到的是您的界面设计不正确。您是否考虑过添加另一个“无”单选按钮,这在逻辑上等同于您的所有单选按钮都没有被选中?为什么不呢?

然而,我确实试图破解你的解决方案,但没有成功。事实上,考虑到我遇到的困难,我非常怀疑即使 可以编程这种行为,你仍然可以更好地寻找替代方案。

我的第一个想法是通过创建自定义wx.RadioButton来覆盖wx.RadioButton处理选择的方式。以下是我发现的一些问题:

  1. wx.EVT_RADIOBUTTON仅在系统已更改单选按钮的值后才被捕获,因此我实际上无法覆盖行为
  2. 按钮捕获wx.EVT_RADIOBUTTON(当没有指定id时),因此无法预测系统是否有进一步排队的更改,这可能会覆盖您对按钮值所做的任何更改。
  3. 如果已选择单选按钮,则不会生成
  4. wx.EVT_RADIOBUTTON
  5. wxPython只有wx.EVT_LEFT_DOWNwx.EVT_LEFT_UP个事件,这两个事件都没有完全描述单选按钮如何知道它被点击了
  6. 然后我转向自定义wx.RadioBox,但我很快意识到没有方法可以完全取消选择收音机盒内的按钮,这意味着它也不是一个可接受的选择。

    我想您可以编写某种包含多个wx.Panel对象的自定义wx.CheckBox,并尝试强制一次只选择最多一个框,但是您再次遇到此问题不是用户希望复选框工作的方式。我以前见过这种行为,但每次它都让我觉得奇怪,我不能推荐它。此外,还需要付出相当大的努力才能发展。

    我能找到的最接近的解决方案是双击时取消选择的自定义wx.RadioButton。这里的问题是用户不希望双击取消选择单选按钮,所以你现在需要考虑如何教他们这个。

    class DeselectableRB(wx.RadioButton):
        def __init__(self, parent, label, pos=None, style=0):
            #do the default init
            wx.RadioButton.__init__(self, parent, label=label, pos=pos, style=style)
    
            #catch double clicks
            self.Bind(wx.EVT_LEFT_DCLICK, self.onDClick)
    
        def onDClick(self, event):
            self.SetValue(0)
    

    但是,我仍然强烈认为标题为“无”的额外wx.RadioButton是您的最佳解决方案,因为它只需要很少的工作量,并且符合用户对单选按钮应如何工作的期望(使其更直观)

答案 1 :(得分:1)

这可以取消选择单选按钮,就像它是一个复选框:

import wx
class MyForm(wx.Frame):
    def __init__(self):
        wx.Frame.__init__(self, None, -1, "Tutorial", size=(300,250))
        panel = wx.Panel(self, wx.ID_ANY)
        self.radio1 = wx.RadioButton(panel, label="A", name='radio1', pos=(20,40), style=wx.RB_GROUP)
        self.radio2 = wx.RadioButton(panel, label="B", name='radio2', pos=(20,70))
        self.radio3 = wx.RadioButton(panel, label="C", name='radio3', pos=(20,100))

        self.radio1.Bind(wx.EVT_LEFT_DOWN, self.OnRB)
        self.radio2.Bind(wx.EVT_LEFT_DOWN, self.OnRB)
        self.radio3.Bind(wx.EVT_LEFT_DOWN, self.OnRB)


        btn = wx.Button(panel, label="Check", pos=(20,140))
        rst = wx.Button(panel, label="Reset", pos=(20,170))
        btn.Bind(wx.EVT_BUTTON, self.onBtn)
        rst.Bind(wx.EVT_BUTTON, self.onRst)

    def OnRB(self, event):
        event.GetEventObject().SetValue(not event.GetEventObject().GetValue())

    def onBtn(self, event):
        print "A = ", self.radio1.GetValue()
        print "B = ", self.radio2.GetValue()
        print "C = ", self.radio3.GetValue()
        print "\n\n"

    def onRst(self, event):
        self.radio1.SetValue( 0 )
        self.radio2.SetValue( 0 )
        self.radio3.SetValue( 0 )

if __name__ == "__main__":
    app = wx.PySimpleApp()
    frame = MyForm().Show()
    app.MainLoop()

请注意,我添加到您的代码中的所有内容都是:

    self.radio1.Bind(wx.EVT_LEFT_DOWN, self.OnRB)
    self.radio2.Bind(wx.EVT_LEFT_DOWN, self.OnRB)
    self.radio3.Bind(wx.EVT_LEFT_DOWN, self.OnRB)

def OnRB(self, event):
    event.GetEventObject().SetValue(not event.GetEventObject().GetValue())