Combo box as grid cell editor
Yusdi Santoso
yusdi at hotmail.com
Wed Aug 1 00:36:57 PDT 2007
Hi all,
I attempted to make combo box as a grid cell editor based on the code given
here:
http://wiki.wxpython.org/index.cgi/wxGridCellChoiceEditor2
by replacing the wx.Choice widget to wx.ComboBox. When nothing else was
changed except for the Choice to ComboBox replacement, the combo box
component failed to be displayed when the cell editor was activated. Tracing
the code I realized that EndEdit was called immediately after BeginEdit
without allowing the combo box to display itself.
I then found a C++ example here:
http://www.wxwidgets.org/wiki/index.php/WxGrid
which is about the same, except that it does not call PushEventHandler on
the combo box. As far as my understanding goes, this seems to mean that all
of the events will be handled directly by the combo box instead of the
window event handler. In any case, removing PushEventHandler allowed the
combo box to be rendered, but...this time the application crashed everytime
it was closed. It seemed to me that the event handling was screwed up by
removing PushEventHandler, but by enabling PushEventHandler, the combo box
was not even displayed.
I though this would be something along this line:
http://wiki.wxpython.org/Surviving_with_wxEVT_KILL_FOCUS_under_Microsoft_Windows
But the suggestions posted there did not seem to work as well.
Any thoughts? I probably just misunderstand the whole event handling
architecture, so any enlightenment will be greatly appreciated.
Thanks,
Yusdi
------------------------------------------------------------------------------
The sample code below will display the combo box on cell edit, but will
crash when the app is closed.
By uncommenting the PushEventHandler, the app will not crash anymore, but
the combo box will not be displayed.
------------------------------------------------------------------------------
import wx
import wx.grid as gridlib
import string
wasClosed = False
#---------------------------------------------------------------------------
class MyCellEditor(gridlib.PyGridCellEditor):
def __init__(self, log, choices, allowOthers):
gridlib.PyGridCellEditor.__init__(self)
self.log = log
self.log.write("MyCellEditor ctor\n")
self.grid = None
self.choices = choices
self.allowOthers = allowOthers
def OnChange(self, evt):
print '--OnChange'
evt.Skip()
def OnSetFocus(self, evt):
print "OnSetFocus"
def Create(self, parent, id, evtHandler):
"""
Called to create the control, which must derive from wxControl.
*Must Override*
"""
self.log.write("MyCellEditor: Create\n")
cbStyle = 0
if not self.allowOthers:
cbStyle = wx.CB_READONLY
self.control = wx.ComboBox(parent, id, '', choices = self.choices,
style=cbStyle)
#self.control.Bind(wx.EVT_COMBOBOX, self.OnChange)
#self.control.Bind(wx.EVT_SET_FOCUS, self.OnSetFocus)
self.SetControl(self.control)
#if evtHandler:
# self.control.PushEventHandler(evtHandler)
def SetCellData(self, row, col, grid):
self.nRow = row
self.nCol = col
self.grid = grid
def BeginEdit(self, row, col, grid):
"""
Fetch the value from the table and prepare the edit control
to begin editing. Set the focus to the edit control.
*Must Override*
"""
self.log.write("MyCellEditor: BeginEdit (%d,%d)\n" % (row, col))
self.startValue = grid.GetTable().GetValue(row, col)
if self.allowOthers:
self.control.SetValue(self.startValue)
else:
pos = self.control.FindString(self.startValue)
if pos==-1:
pos = 0
self.control.SetSelection(pos)
self.control.SetInsertionPointEnd()
self.control.SetFocus()
self.SetCellData(row, col, grid)
def EndEdit(self, row, col, grid):
"""
Complete the editing of the current cell. Returns True if the value
has changed. If necessary, the control may be destroyed.
*Must Override*
"""
self.log.write("MyCellEditor: EndEdit (%d,%d)\n" % (row, col))
value = self.control.GetValue()
changed = value!=grid.GetTable().GetValue(row, col)
if changed:
grid.GetTable().SetValue(row, col, value)
self.startValue = ''
if self.allowOthers:
self.control.SetValue(self.startValue)
else:
self.control.SetSelection(0)
return changed
def Reset(self):
"""
Reset the value in the control back to its starting value.
*Must Override*
"""
self.log.write("MyCellEditor: Reset\n")
self.control.SetValue(self.startValue)
self.control.SetInsertionPointEnd()
def SetParameters(self, params):
if len(params)>0:
self.choices = params
def IsAcceptedKey(self, evt):
return (not (evt.ControlDown() or evt.AltDown()) and
evt.GetKeyCode() != wx.WXK_SHIFT)
def StartingKey(self, evt):
key = evt.GetKeyCode()
ch = None
if key in [wx.WXK_NUMPAD0, wx.WXK_NUMPAD1, wx.WXK_NUMPAD2,
wx.WXK_NUMPAD3, wx.WXK_NUMPAD4,
wx.WXK_NUMPAD5, wx.WXK_NUMPAD6, wx.WXK_NUMPAD7,
wx.WXK_NUMPAD8, wx.WXK_NUMPAD9]:
ch = ch = chr(ord('0') + key - wx.WXK_NUMPAD0)
elif key < 256 and key >= 0 and chr(key) in string.printable:
ch = chr(key)
if not evt.ShiftDown():
ch = ch.lower()
if ch is not None:
self.control.SetStringSelection(ch)
else:
evt.Skip()
def Clone(self):
"""
Create a new object which is the copy of this one
*Must Override*
"""
self.log.write("MyCellEditor: Clone\n")
return MyCellEditor(self.log, self.choices, self.allowOthers)
#---------------------------------------------------------------------------
class GridEditorTest(gridlib.Grid):
def __init__(self, parent, log):
gridlib.Grid.__init__(self, parent, -1)
self.log = log
self.CreateGrid(10, 3)
# Somebody changed the grid so the type registry takes precedence
# over the default attribute set for editors and renderers, so we
# have to set null handlers for the type registry before the
# default editor will get used otherwise...
#self.RegisterDataType(wxGRID_VALUE_STRING, None, None)
#self.SetDefaultEditor(MyCellEditor(self.log))
# Or we could just do it like this:
#self.RegisterDataType(wxGRID_VALUE_STRING,
# wxGridCellStringRenderer(),
# MyCellEditor(self.log))
# but for this example, we'll just set the custom editor on one cell
choices = ['banana', 'apple', 'orange']
self.SetCellEditor(1, 0, MyCellEditor(self.log, choices, True))
self.SetCellValue(1, 0, "11")
# and on a column
attr = gridlib.GridCellAttr()
attr.SetEditor(MyCellEditor(self.log, choices, True))
self.SetColAttr(2, attr)
self.SetCellValue(1, 2, "two")
self.SetColSize(0, 150)
self.SetColSize(1, 150)
self.SetColSize(2, 75)
#---------------------------------------------------------------------------
class TestFrame(wx.Frame):
def __init__(self, parent, log):
wx.Frame.__init__(self, parent, -1, "Custom Grid Cell Editor Test",
size=(640,480))
grid = GridEditorTest(self, log)
wx.EVT_CLOSE(self, self.OnCloseFrame)
def OnCloseFrame(self, evt):
win = wx.Window.FindFocus()
if win != None:
win.Disconnect(-1, -1, wx.wxEVT_KILL_FOCUS)
self.Destroy()
#---------------------------------------------------------------------------
if __name__ == '__main__':
import sys
app = wx.PySimpleApp()
frame = TestFrame(None, sys.stdout)
frame.Show(True)
app.MainLoop()
_________________________________________________________________
Don't get caught with egg on your face. Play Chicktionary!
http://club.live.com/chicktionary.aspx?icid=chick_hotmailtextlink2
More information about the wxpython-users
mailing list