【问题标题】:wxPython, radio button selection/deselection and wx.RB_GROUPwxPython,单选按钮选择/取消选择和 wx.RB_GROUP
【发布时间】:2013-02-13 22:19:26
【问题描述】:

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

我有三个单选按钮绑定在一个组中,我看到这让我可以选择单选按钮 A、B 或 C,其中一个总是被选中 - 我很欣赏这就是 wx.RB_GROUP 的本质风格;

是否可以仅通过单击单选按钮来取消选择 A=B=C=False 中的所有按钮?我已经简化了代码(如下),其中 Reset 按钮执行此功能,但理想情况下我只想在 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()

【问题讨论】:

    标签: wxpython radio-button


    【解决方案1】:

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

    但是,我确实试图破解您的解决方案,但没有成功。事实上,考虑到我面临的困难,我高度怀疑即使 可以对这种行为进行编程,你最好还是找到一个替代方案。

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

    1. wx.EVT_RADIOBUTTON 仅在系统已经更改了单选按钮的值之后才被捕获,因此我实际上无法覆盖行为
    2. 按钮在不同时间捕获wx.EVT_RADIOBUTTON(未指定id),因此无法预测系统是否有进一步的更改排队,这可能会覆盖您对按钮值所做的任何更改。
    3. 如果已选择单选按钮,则不会生成wx.EVT_RADIOBUTTON
    4. wxPython 只有wx.EVT_LEFT_DOWNwx.EVT_LEFT_UP 事件,它们都没有完全描述单选按钮如何知道它已被点击

    然后我转向自定义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 是您的最佳解决方案,因为它需要的工作量最少,并且符合用户对单选按钮应如何工作的期望(使其更直观)。

    【讨论】:

    • 非常感谢您花时间查看,是的,自定义单选按钮与我的重置功能相同:def onRst(self, event): self.radio1.SetValue(0)
    【解决方案2】:

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

    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())
    

    【讨论】:

      猜你喜欢
      • 2015-08-26
      • 2016-05-25
      • 2011-07-17
      • 2013-10-01
      • 2012-02-21
      • 1970-01-01
      • 2018-07-15
      • 1970-01-01
      • 2015-07-01
      相关资源
      最近更新 更多