This week I spent some time learning how to add check boxes to the ObjectListView widget in wxPython. If you don’t know, ObjectListView is a 3rd party wrapper for the wx.ListCtrl widget that makes using the ListCtrl much easier. You can read all about it in this older article from the archives. I had a requirement where I needed to have a check box next to each item in the report view of the widget. After some digging on the ObjectListView website, I found an article that sort of explained how to do it. According to the documentation, I could use the CreateCheckStateColumn method or register a column and use InstallCheckStateColumn. In this article, we’ll be focusing on the CreateCheckStateColumn method.
Getting Started
First off, you’ll need to install the following if you haven’t done so already:
- wxPython
- ObjectListView from the Python Package Index
How to Create and Toggle Checkboxes
Now that you’ve got that done, we can begin coding. I always found a working example to be the best way to learn, so here’s the first piece of the puzzle:
# OLVcheckboxes.py import wx from ObjectListView import ObjectListView, ColumnDefn ######################################################################## class Results(object): """""" #---------------------------------------------------------------------- def __init__(self, tin, zip_code, plus4, name, address): """Constructor""" self.tin = tin self.zip_code = zip_code self.plus4 = plus4 self.name = name self.address = address ######################################################################## class ProvPanel(wx.Panel): """""" #---------------------------------------------------------------------- def __init__(self, parent): """Constructor""" wx.Panel.__init__(self, parent=parent) mainSizer = wx.BoxSizer(wx.VERTICAL) self.test_data = [Results("123456789", "50158", "0065", "Patti Jones", "111 Centennial Drive"), Results("978561236", "90056", "7890", "Brian Wilson", "555 Torque Maui"), Results("456897852", "70014", "6545", "Mike Love", "304 Cali Bvld") ] self.resultsOlv = ObjectListView(self, style=wx.LC_REPORT|wx.SUNKEN_BORDER) self.setResults() toggleBtn = wx.Button(self, label="Toggle Checks") toggleBtn.Bind(wx.EVT_BUTTON, self.onToggle) mainSizer.Add(self.resultsOlv, 1, wx.EXPAND|wx.ALL, 5) mainSizer.Add(toggleBtn, 0, wx.CENTER|wx.ALL, 5) self.SetSizer(mainSizer) #---------------------------------------------------------------------- def onToggle(self, event): """ Toggle the check boxes """ objects = self.resultsOlv.GetObjects() for obj in objects: print self.resultsOlv.IsChecked(obj) self.resultsOlv.ToggleCheck(obj) self.resultsOlv.RefreshObjects(objects) #---------------------------------------------------------------------- def setResults(self): """""" self.resultsOlv.SetColumns([ ColumnDefn("TIN", "left", 100, "tin"), ColumnDefn("Zip", "left", 75, "zip_code"), ColumnDefn("+4", "left", 50, "plus4"), ColumnDefn("Name", "left", 150, "name"), ColumnDefn("Address", "left", 200, "address") ]) self.resultsOlv.CreateCheckStateColumn() self.resultsOlv.SetObjects(self.test_data) ######################################################################## class ProvFrame(wx.Frame): """""" #---------------------------------------------------------------------- def __init__(self): """Constructor""" title = "OLV Checkbox Tutorial" wx.Frame.__init__(self, parent=None, title=title, size=(1024, 768)) panel = ProvPanel(self) #---------------------------------------------------------------------- if __name__ == "__main__": app = wx.App(False) frame = ProvFrame() frame.Show() app.MainLoop()
Let’s break this down a little. As you can see, we put the wx.Frame and the wx.Panel into separate classes. This makes it easier to modularize in the future if need be. For example, if the panel code got to be too many lines, we could just copy it into a new module and import it into the main code. Anyway, here we create the various widgets we care about in the panel class’s __init__ method. To get check boxes, we need to add the CreateCheckStateColumn call right before the SetObjects call which is in the setResults method.
The other important method we care about is the onToggle method where we learn how to toggle the check boxes using the ToggleCheck method. We start out by grabbing all the item object in the widget via GetObjects and then we loop over them. In this example, we print out whether they’re checked or not by using the handy IsChecked method. This is useful for debugging or if you want to toggle items individually based on their state. Lastly, you need to call RefreshObjects to refresh the ObjectListCtrl so you can see the check box’s new state. Otherwise, the display doesn’t update and you cannot tell if the items are checked or not. You can also toggle the check boxes by selecting the item(s) and pressing the spacebar.
Toggling the Checkboxes with SetCheckState
There is another way to change the check box’s state and that is to use the SetCheckState method. Here’s some code demonstrating how it is accomplished:
# OLVcheckboxes2.py import wx from ObjectListView import ObjectListView, ColumnDefn ######################################################################## class Results(object): """""" #---------------------------------------------------------------------- def __init__(self, tin, zip_code, plus4, name, address): """Constructor""" self.tin = tin self.zip_code = zip_code self.plus4 = plus4 self.name = name self.address = address ######################################################################## class OLVCheckPanel(wx.Panel): """""" #---------------------------------------------------------------------- def __init__(self, parent): """Constructor""" wx.Panel.__init__(self, parent=parent) mainSizer = wx.BoxSizer(wx.VERTICAL) btnSizer = wx.BoxSizer(wx.HORIZONTAL) self.test_data = [Results("123456789", "50158", "0065", "Patti Jones", "111 Centennial Drive"), Results("978561236", "90056", "7890", "Brian Wilson", "555 Torque Maui"), Results("456897852", "70014", "6545", "Mike Love", "304 Cali Bvld") ] self.resultsOlv = ObjectListView(self, style=wx.LC_REPORT|wx.SUNKEN_BORDER) self.setResults() checkBtn = wx.Button(self, label="Check") checkBtn.Bind(wx.EVT_BUTTON, self.onCheck) btnSizer.Add(checkBtn, 0, wx.ALL, 5) uncheckBtn = wx.Button(self, label="Uncheck") uncheckBtn.Bind(wx.EVT_BUTTON, self.onUncheck) btnSizer.Add(uncheckBtn, 0, wx.ALL, 5) mainSizer.Add(self.resultsOlv, 1, wx.EXPAND|wx.ALL, 5) mainSizer.Add(btnSizer, 0, wx.CENTER|wx.ALL, 5) self.SetSizer(mainSizer) #---------------------------------------------------------------------- def onCheck(self, event): """""" objects = self.resultsOlv.GetObjects() for obj in objects: self.resultsOlv.SetCheckState(obj, True) self.resultsOlv.RefreshObjects(objects) #---------------------------------------------------------------------- def onUncheck(self, event): """""" objects = self.resultsOlv.GetObjects() for obj in objects: self.resultsOlv.SetCheckState(obj, False) self.resultsOlv.RefreshObjects(objects) #---------------------------------------------------------------------- def setResults(self): """""" self.resultsOlv.SetColumns([ ColumnDefn("TIN", "left", 100, "tin"), ColumnDefn("Zip", "left", 75, "zip_code"), ColumnDefn("+4", "left", 50, "plus4"), ColumnDefn("Name", "left", 150, "name"), ColumnDefn("Address", "left", 200, "address") ]) self.resultsOlv.CreateCheckStateColumn() self.resultsOlv.SetObjects(self.test_data) ######################################################################## class OLVCheckFrame(wx.Frame): """""" #---------------------------------------------------------------------- def __init__(self): """Constructor""" title = "OLV Checkbox Tutorial" wx.Frame.__init__(self, parent=None, title=title, size=(1024, 768)) panel = OLVCheckPanel(self) #---------------------------------------------------------------------- if __name__ == "__main__": app = wx.App(False) frame = OLVCheckFrame() frame.Show() app.MainLoop()
As you can see, we have two buttons in this example. A Check and an Uncheck button. The code is basically the same, but this time when we loop over the objects we call SetCheckState and pass it the item object and a bool of either True or False. Then we refresh the screen as before.
Wrapping Up
Now you know how to add check boxes to your wxPython project if you’re using ObjectListView. If you need to use check boxes in the normal wx.ListCtrl, you can use a mixin that’s included with wx. Here’s how you access it:
from wx.lib.mixins.listctrl import CheckListCtrlMixin
There is an example in the wxPython demo package, which you can download from the wxPython website. I suspect that you could also use check boxes in the DVCListCtrl with that mixin as well or you could get very customized with the UltimateListCtrl. I prefer using the ObjectListView control as of right now though. I tested this code using Python 2.6.6 and Python 2.7.3 with wxPython 2.8.12 and wxPython 2.9.4 classic. I also used ObjectListview 1.2.
Further Reading
- The ObjectListView cookbook
- wxPython: Using ObjectListView instead of a ListCtrl
Downloads