WxPython - fire checkbox event when setting its value in code

Consider the following piece of code:

import wx

class MyFrame(wx.Frame):
    def __init__(self, *args, **kwds):
        wx.Frame.__init__(self, *args, **kwds)
        self.cb1 = wx.CheckBox(self, -1, "CheckBox 1")
        self.cb2 = wx.CheckBox(self, -1, "CheckBox 2")
        self.cb3 = wx.CheckBox(self, -1, "CheckBox 3")

        sizer = wx.BoxSizer(wx.VERTICAL)
        sizer.Add(self.cb1, 0, wx.ADJUST_MINSIZE, 0)
        sizer.Add(self.cb2, 0, wx.ADJUST_MINSIZE, 0)
        sizer.Add(self.cb3, 0, wx.ADJUST_MINSIZE, 0)

        self.SetSizer(sizer)
        self.Layout()

        self.Bind(wx.EVT_CHECKBOX, self.OnCb1, self.cb1)
        self.Bind(wx.EVT_CHECKBOX, self.OnCb2, self.cb2)

    def OnCb1(self, evt):
        self.cb2.SetValue(evt.IsChecked())

    def OnCb2(self, evt):
        self.cb3.SetValue(evt.IsChecked())


if __name__ == "__main__":
    app = wx.PySimpleApp(0)
    frame = MyFrame(None, -1, "")
    app.SetTopWindow(frame)
    frame.Show()
    app.MainLoop()

      

Here I have 3 checkboxes tied together, so it cb2

checks when cb1

it does and cb3

gets the checkbox if cb2

it does. However, when I set the value cb2

in the subroutine OnCb1

, the checkbox event is cb2

not fired and the checkbox is cb3

not checked. So I would like to find a way to trigger somehow the event cb2

manually so that all 3 fields are checked at once when validating only cb1

. I would be very grateful if someone can tell me.

+3


source to share


3 answers


Use wx.PostEvent ... like so:



class launcherWindow(wx.Frame):
    def __init__(self):
        wx.Frame.__init__(self, parent=None, title='New Window')
        #now add the main body, start with a panel
        panel = wx.Panel(self)
        #instantiate a new dropdown
        self.productDropDown = wx.ComboBox(panel, size=wx.DefaultSize, style = wx.CB_READONLY)

        #get the products and product subtypes
        self.productDict = self.getProductsAndSubtypes()

        #setup subtypes first, just in case, since onProductSelection will reference this
        self.productSubtypeDropDown = wx.ComboBox(panel, size=wx.DefaultSize, style = wx.CB_READONLY)

        #add products
        for product in self.productDict.keys():
            self.productDropDown.Append(product)

        #bind selection event
        self.productDropDown.Bind(wx.EVT_COMBOBOX, self.onProductSelection)

        #set default selection
        self.productDropDown.SetSelection(0)

        #pretend that we clicked the product selection, so it event gets called
        wx.PostEvent(self.productDropDown, wx.CommandEvent(wx.wxEVT_COMMAND_COMBOBOX_SELECTED))

        #now add the dropdown to a sizer, set the sizer for the panel, fit the panel, etc...

    def onProductSelection(self, event):
        productSelected = self.productDropDown.GetStringSelection()
        productSubtypes = self.productDict[productSelected]

        #clear any existing product subtypes, since each product may have different ones
        self.productSubtypeDropDown.Clear()

        for productSubtype in productSubtypes:
            self.productSubtypeDropDown.Append(productSubtype)

        #select the first item by default
        self.productSubtypeDropDown.SetSelection(0)

      

+3


source


I couldn't accept the nmz787 code directly and had to hack a bit, but I finally got it for

  • changing the state of the checkbox and
  • having a checkbox receives the event

as if the user clicked on it.



I thought I'd post my code in case others get stuck trying to get this to work. Since it only depended on the checkbox and not on which one was calling it, I accounted for it as an independent "top-level" function, not as a method for any class.

def toggleCheckBox(cb):
    evt = wx.CommandEvent(commandType=wx.EVT_CHECKBOX.typeId)
    evt.SetEventObject(cb)
    cb.SetValue( not cb.GetValue())
    wx.PostEvent(cb, evt)

      

I have no idea why the CommandEvent constructor needs the keyword, or if there is a smarter, more reliable way to get the required typeId, but it worked for me.

+1


source


I have no experience with wxPython, so I cannot give you a specific example, but I know that setting a value programmatically will not trigger command events for widgets. My guess is that you will have to manually place the event for cb2 after you set its value. You can view a similar question here: wxPython: Calling an Event Manually

What I can suggest is to subclass wx.CheckBox and create a method SetValueWithEvent()

or similar method that will call SetValue and post the event wx. EVT_CHECKBOX

.

PyQt has similar situations where signals may or may not be thrown when programmatically defining values โ€‹โ€‹in widgets. They sometimes give you more than one signal that you can listen to to place anyway. Unfortunately, based only on my limited involvement with the wxPython examples, I think it is much more primitive and slightly less pythonic. So you seem to have to do things yourself a little more often.

0


source







All Articles