Search code examples
event-handlingwxpython

Is there an efficient way to handle multiple checkboxes that change one variable in wxPython?


I am working on a wxPython application with quite a lot of user-changeable options. That leads to a lot of checkboxes which need to be handled in some way.

At the time, my code looks something like this:

        self.checkbox1=wx.CheckBox(self.panel,label='Do X')
        self.checkbox1.Bind(wx.EVT_CHECKBOX,self.DoXCheckboxHandler)
        self.checkbox1.SetValue(True)
        self.sizer.Add(self.checkbox1,0,wx.ALL|wx.EXPAND,5)

        self.checkbox2=wx.CheckBox(self.panel,label='Do Y')
        self.checkbox2.Bind(wx.EVT_CHECKBOX,self.DoYCheckboxHandler)
        self.checkbox2.SetValue(True)
        self.sizer.Add(self.checkbox2,0,wx.ALL|wx.EXPAND,5)
...
    def DoXCheckboxHandler(self,event):
        self.DoX=self.checkbox1.GetValue()
        self.RefreshUserView(self)

    def DoYCheckboxHandler(self,event):
        self.DoY=self.checkbox2.GetValue()
        self.RefreshUserView(self)
...

Is there any more efficient way (in terms of code-length) of handling multiple checkboxes, which all practically change only one variable and then call one and the same function? My approach, although working fine, seems like having a lot of unnecessary(?) repetition.

Certainly one way to do it would be to skip the "extra" variable altogether - however, in practice I need to have those variables separately from the widgets - as I need the values even if the widgets are destroyed (after closing the options frame, for example).

All advice will be appreciated.


Solution

  • You may want to edit the question title, "handle multiple checkboxes that change one variable" as it does not seem to fit with the following text. There appear to be multiple variables.
    That being the case, one of the easiest methods is to store the variable names and values in a dictionary and update the value using the event objects GetName() function.
    Here is an example:

    import wx
    import wx.lib.agw.ultimatelistctrl as ULC
    
    class MyFrame(wx.Frame):
        def __init__(self, parent):
            wx.Frame.__init__(self, parent, -1, "Days and Hours Checkbox Grid", size=(600,300))
            agwStyle = (ULC.ULC_HAS_VARIABLE_ROW_HEIGHT | wx.LC_REPORT | wx.LC_VRULES | wx.LC_HRULES | wx.LC_SINGLE_SEL)
            self.mylist = mylist = ULC.UltimateListCtrl(self, wx.ID_ANY, agwStyle=agwStyle)
    
            # Load headings
            mylist.InsertColumn(0,"Weekday", width=100)
            for col in range(1,25):
                col_num=str(col-1)
                mylist.InsertColumn(col,col_num, width=20)
    
            # Dictionary to Store checkbox variable names and values
            self.variables = {}
    
            # Load Side headings
            days=['Monday','Tuesday','Wednesday','Thursday','Friday','Saturday','Sunday']
            for day in range(7):
                mylist.InsertStringItem(day, str(days[day]))
    
            # Load checkboxes
            for boxes in range(1,25):
                for index in range(7):
                    day = days[index]
                    hour = boxes-1
                    name_of_checkbox = "{day}_{hour}".format(day=day, hour=hour)
                    self.checkBox = wx.CheckBox(mylist, wx.ID_ANY, "", wx.DefaultPosition, wx.DefaultSize, 0,name=name_of_checkbox)
            # Store individual checkbox variable names and values in a dictionary
                    self.variables[name_of_checkbox] = False
    
                    mylist.SetItemWindow(index, boxes, self.checkBox)
    
            sizer = wx.BoxSizer(wx.VERTICAL)
            sizer.Add(mylist, 1, wx.EXPAND)
            button = wx.Button(self,-1,"Print Data")
            sizer.Add(button)
            self.Bind(wx.EVT_CHECKBOX, self.OnChecked)
            self.Bind(wx.EVT_BUTTON, self.OnGetData)
            self.SetSizer(sizer)
    
        def OnChecked(self,event):
            clicked = event.GetEventObject()
            variable_name = clicked.GetName()
            self.variables[variable_name] = event.IsChecked()
            if event.IsChecked():
                print(variable_name,"from False to True")
            else:
                print(variable_name,"from True to False")
    
        def OnGetData(self,event):
            for i,v in self.variables.items():
                print(i,v)
    
    app = wx.App()
    frame = MyFrame(None)
    frame.Show()
    app.MainLoop()
    

    enter image description here