7

I'm trying to capture keyboard events that happen inside a wx.Frame, and I would expect the following code to capture those events. However, the handler OnKeyDown is never called when I run the code:

import logging as log
import wx

class MainWindow(wx.Frame):
    def __init__(self, parent, title):
        wx.Frame.__init__(self, parent, title=title, size=(200,100))

        self.Bind(wx.EVT_KEY_DOWN, self.OnKeyDown)
        self.Bind(wx.EVT_KEY_UP, self.OnKeyDown)
        self.Bind(wx.EVT_CHAR, self.OnKeyDown)
        self.SetFocus()
        self.Show(True)

    def OnKeyDown(self, event=None):
        log.debug("OnKeyDown event %s" % (event))

if __name__ == "__main__":
    app = wx.App(False)
    gui = MainWindow(None, "test")
    app.MainLoop()

If anyone knows how to do this, I would appreciate some help.

Kevin
  • 1,080
  • 3
  • 15
  • 41

2 Answers2

10

I figured out that I can add a panel to the frame, and a panel is much more receptive of keyboard events.

import wx

class MainWindow(wx.Frame):
    def __init__(self, parent, title):
        wx.Frame.__init__(self, parent, title=title, size=(200,100))

        self.panel = wx.Panel(self, wx.ID_ANY)
        self.panel.Bind(wx.EVT_KEY_DOWN, self.OnKeyDown)
        self.panel.Bind(wx.EVT_KEY_UP, self.OnKeyDown)
        self.panel.Bind(wx.EVT_CHAR, self.OnKeyDown)
        self.panel.SetFocus()
        self.Show(True)

    def OnKeyDown(self, event=None):
        print "Event!"

if __name__ == "__main__":
    app = wx.App(False)
    gui = MainWindow(None, "test")
    app.MainLoop()
Kevin
  • 1,080
  • 3
  • 15
  • 41
  • @joaquin: Not sure if *sensitivity* is the best term, but this is a good answer. I had the same problem on Ubuntu, couldn't capture key events with a `wx.Frame`. Adding a `wx.Panel` along with a `SetFocus()` on it solved the issue. – shinjin Oct 20 '14 at 03:08
3

Your code works if you use log.warning.

log.warning("OnKeyDown event %s" % (event))

Logging levels are:

Level    Value
CRITICAL  50
ERROR     40
WARNING   30
INFO      20
DEBUG     10
UNSET      0

The default logging level is WARNING. Only logs with levels higher than the default are produced. So, at the default level (30), neither log.info nor log.debug produce any output.

Edited after OP comments: Setting the correct level of logging make your code works perfect on winXP 32bit and win7 64bit with python 2.6 and wxpython 2.8.11 and 2.8.12. The code however doesn't work on ubuntu for some reason I don't know. This difference is related with how wxwidgets is implemented in different SO's but not with logging. As you already discovered, for it to work in ubuntu, it needs a panel to be added as well as the use of the adequate logging level. So this works:

class MainWindow(wx.Frame):
    def __init__(self, parent, title):
        wx.Frame.__init__(self, parent, title=title, size=(200,100))
        self.panel =  wx.Panel(self, wx.ID_ANY)
        self.Bind(wx.EVT_KEY_DOWN, self.KeyDown)
        self.Bind(wx.EVT_KEY_UP, self.KeyDown)
        self.Bind(wx.EVT_CHAR, self.KeyDown)
        self.panel.SetFocus()

    def KeyDown(self, event=None):
        logging.warning("OnKeyDown event %s" % (event))

if __name__ == "__main__":
    app = wx.App(False)
    gui = MainWindow(None, "test")
    gui.Show()
    app.MainLoop()
joaquin
  • 82,968
  • 29
  • 138
  • 152
  • 1
    I tried making this change, and also tried not using the logging package - just print. Neither change worked. – Kevin Jan 11 '12 at 07:21
  • @Kevin, do you mean the code in your answer works and the one in your question or my answer do not, even eliminating logging ? What SO, python and wxPython versions are you using ?. This is tested in win7 and winXP, python 2.6, wxpython 2.8.11 and 2.8.12 – joaquin Jan 11 '12 at 13:10
  • I am using Ubuntu 11.04 64bit, as it looks like you have already deduced. So it's a quirk based on the OS, but adding the panel to the frame is an easy work-around. – Kevin Jan 12 '12 at 00:27