Introduction

wxPython includes a wx.GridCellBoolEditor/Renderer, which looks like a wx.CheckBox

Unfortunately it does not behave exactly like a wx.CheckBox, for two reasons -

1, You have to click it twice with a mouse to change it - once to create the Editor, a second time to change the value

2. There is no obvious way to detect that the value has changed until the Editor is closed

What Objects are Involved

wx.grid.Grid

wx.grid.GridCellBoolEditor

wx.grid.GridCellBoolRenderer

Process Overview

The example assumes that you want all cells in Column 1 to act like a wx.CheckBox.

The grid's init() method sets up the Editor and Renderer for Column 1 in a Column Attribute.

To solve problem 1 above, when a mouse click is detected in Column 1, wx.CallLater is used to call a method to toggle the value, with a delay of 100 (1/10 sec). This gives enough time for the Editor to be created first.

To solve problem 2 above, an EVT_GRID_EDITOR_CREATED handler is used to obtain and save a reference to the underlying wx.CheckBox, and set up an EVT_CHECKBOX handler for it.

A method called afterCheckBox() is used to respond to any changes to the wx.CheckBox. It is called both from the initial mouse click and from EVT_CHECKBOX.

Code Sample

   1 import wx, wx.grid as grd
   2 
   3 class MyGrid(grd.Grid):
   4     def __init__(self, parent):
   5         grd.Grid.__init__(self, parent, -1, pos=(10,40), size=(420,95))
   6 
   7         self.CreateGrid(3,3)
   8         self.RowLabelSize = 0
   9         self.ColLabelSize = 20
  10 
  11         attr = grd.GridCellAttr()
  12         attr.SetEditor(grd.GridCellBoolEditor())
  13         attr.SetRenderer(grd.GridCellBoolRenderer())
  14         self.SetColAttr(1,attr)
  15         self.SetColSize(1,20)
  16 
  17         self.Bind(grd.EVT_GRID_CELL_LEFT_CLICK,self.onMouse)
  18         self.Bind(grd.EVT_GRID_SELECT_CELL,self.onCellSelected)
  19         self.Bind(grd.EVT_GRID_EDITOR_CREATED, self.onEditorCreated)
  20 
  21     def onMouse(self,evt):
  22         if evt.Col == 1:
  23             wx.CallLater(100,self.toggleCheckBox)
  24         evt.Skip()
  25 
  26     def toggleCheckBox(self):
  27         self.cb.Value = not self.cb.Value
  28         self.afterCheckBox(self.cb.Value)
  29 
  30     def onCellSelected(self,evt):
  31         if evt.Col == 1:
  32             wx.CallAfter(self.EnableCellEditControl)
  33         evt.Skip()
  34 
  35     def onEditorCreated(self,evt):
  36         if evt.Col == 1:
  37             self.cb = evt.Control
  38             self.cb.WindowStyle |= wx.WANTS_CHARS
  39             self.cb.Bind(wx.EVT_KEY_DOWN,self.onKeyDown)
  40             self.cb.Bind(wx.EVT_CHECKBOX,self.onCheckBox)
  41         evt.Skip()
  42 
  43     def onKeyDown(self,evt):
  44         if evt.KeyCode == wx.WXK_UP:
  45             if self.GridCursorRow > 0:
  46                 self.DisableCellEditControl()
  47                 self.MoveCursorUp(False)
  48         elif evt.KeyCode == wx.WXK_DOWN:
  49             if self.GridCursorRow < (self.NumberRows-1):
  50                 self.DisableCellEditControl()
  51                 self.MoveCursorDown(False)
  52         elif evt.KeyCode == wx.WXK_LEFT:
  53             if self.GridCursorCol > 0:
  54                 self.DisableCellEditControl()
  55                 self.MoveCursorLeft(False)
  56         elif evt.KeyCode == wx.WXK_RIGHT:
  57             if self.GridCursorCol < (self.NumberCols-1):
  58                 self.DisableCellEditControl()
  59                 self.MoveCursorRight(False)
  60         else:
  61             evt.Skip()
  62 
  63     def onCheckBox(self,evt):
  64         self.afterCheckBox(evt.IsChecked())
  65 
  66     def afterCheckBox(self,isChecked):
  67         print 'afterCheckBox',self.GridCursorRow,isChecked
  68 
  69 class TestFrame(wx.Frame):
  70     def __init__(self, parent):
  71         wx.Frame.__init__(self, parent, -1, "Custom cell editor test", size=(250,200))
  72         panel = wx.Panel(self,style=0)
  73         grid = MyGrid(panel)
  74         grid.SetFocus()
  75         self.CentreOnScreen()
  76 
  77 class MyApp(wx.App):
  78     def OnInit(self):
  79         frame = TestFrame(None)
  80         frame.Show(True)
  81         self.SetTopWindow(frame)
  82         return True
  83 
  84 MyApp(0).MainLoop()

Comments

If anything is not clear, ask questions here and I will do my best to answer them.

Frank Millman

Change wxGrid CheckBox with one click (last edited 2008-03-11 10:50:20 by localhost)

NOTE: To edit pages in this wiki you must be a member of the TrustedEditorsGroup.