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