python-3.xeventstextwxpythonwxgrid

Key event detecting in grid - wxPython


I created a grid using wxPython and I need to monitor the data inserted by the user into one of the cells in my grid. I need to have an event due to every key press in the keyboard (like EVT_KEY_DOWN) and I can't find a way to do that. Right now I need to use a grid for this purpose so the solution must be something that can be integrated into wx.grid.

I tried to use GridCellEditor but it only gives the first key. Is there a way to integrate TextCtrl into a grid's cell or something like that?


Solution

  • As far as I can tell, unless told differently, a grid is a collection of TextCtrl's, so the key is to bind wx.EVT_KEY_DOWN to them.
    Here is one way to do it:
    Note: I have added a few different element types for demonstration purposes.
    Hopefully this is all that you require.

    import wx
    import wx.grid as gridlib
    class MyForm(wx.Frame):
        def __init__(self):
            wx.Frame.__init__(self, None, wx.ID_ANY, "A key detecting grid", size=(1000,300))
            panel = wx.Panel(self, wx.ID_ANY)
            self.grid = gridlib.Grid(panel)
            self.grid.CreateGrid(10, 8)
            self.grid.Bind(wx.EVT_KEY_DOWN, self.OnKeyPress) #Required for initial key press
            self.grid.Bind(gridlib.EVT_GRID_EDITOR_CREATED, self.onEditorCreated) # For subsequent key presses
    
        # -- Additional bits only for demonstration of isolating Text fields
    
            # Boolean field dislays as a CheckBox
            crbool = wx.grid.GridCellBoolRenderer()
            cebool = wx.grid.GridCellBoolEditor()
            self.grid.SetCellRenderer(1, 1, crbool)
            self.grid.SetCellEditor(1, 1, cebool)
            # Choice field
            cechoice = wx.grid.GridCellChoiceEditor(['Choice 1','Choice 2','Choice 3'], allowOthers=False)
            self.grid.SetCellEditor(1, 2, cechoice)
            #Load special fields
            self.grid.SetCellValue(1, 1, '1')
            self.grid.SetCellValue(1, 2, 'Choice 2')
            self.grid.SetColSize(0,200)
            self.grid.SetColSize(2,200)
    
        # --
            sizer = wx.BoxSizer(wx.VERTICAL)
            sizer.Add(self.grid, 1, wx.EXPAND, 5)
            panel.SetSizerAndFit(sizer)
            self.Show()
    
        def OnKeyPress(self, event):
            uk = event.UnicodeKey
            key = chr(event.UnicodeKey)
            shift = event.shiftDown
            if not shift:
                key = key.lower()
            print("Key", uk, key)
            event.Skip()
    
        def onEditorCreated(self,event):
            #Set TextCtrl element to want all char/key events for all keys
            self.cb = event.Control
            if event.Control.ClassName == "wxTextCtrl":
                self.cb.SetWindowStyle(wx.WANTS_CHARS) # BEWARE! - Returns Tab, Enter, Arrow keys etc
                self.cb.Bind(wx.EVT_KEY_DOWN,self.OnKeyPress)
            else:
                print("Non text cell - bailing out")
            event.Skip()
    
    if __name__ == "__main__":
        app = wx.App()
        frame = MyForm()
        app.MainLoop()
    

    enter image description here