Cannot get wxPython to capture (some) keystrokes

Question:

I’ve been having some issues with a new application I’m writing for work, in Python (3.8) and wxPython (4.1.0), regarding detecting key presses (it doesn’t). This is under Windows 10.

Thinking it may be my control hierarchy "swallowing" events, I found a simple example on the web to test and it appears it has the same problem. The code is below:

import wx

class TestPanel(wx.Panel):
    def __init__(self, *args, **kwds):
        wx.Panel.__init__(self, *args, **kwds)
        sizer=wx.BoxSizer(wx.VERTICAL)
        sizer.SetMinSize((300, 200))
        self.Text = wx.StaticText(self, label="Key Testsn")
        sizer.Add(self.Text, 1, wx.EXPAND | wx.GROW | wx.ALL, 10)
        self.SetSizerAndFit(sizer)
        self.Layout()
        self.SetFocus()

        print("binding")
        self.Bind(wx.EVT_CHAR, self.OnKey)
        print("bound")

    def OnKey(self, event):
        print("called")
        print(event)
        lbl = f"{self.Text.GetLabel()}{event.GetKeyCode()}n"
        self.Text.SetLabel(lbl)
        event.Skip()

class TestFrame(wx.Frame):
    def __init__(self, *args, **kwds):
        wx.Frame.__init__(self, *args, **kwds)

        panel = TestPanel(self, wx.ID_ANY)
        sizer=wx.BoxSizer(wx.VERTICAL)
        sizer.Add(panel, 1, wx.EXPAND)
        self.SetSizerAndFit(sizer)
        self.Layout()

class TestApp(wx.App):
    def OnInit(self):
        mainFrame = TestFrame(None, -1, "Test")
        self.SetTopWindow(mainFrame)
        mainFrame.Show()
        return 1

app = TestApp()
app.MainLoop()

When run, it creates the frame but no amount of pressing keys (but see below) results in the output from OnKey() being generated:

enter image description here

The "see below" bit is a minor modification to that statement when I press the Windows key to run the snipping tool for capturing that image above – that’s what caused the 393 to appear in the window and gave me output of:

binding
bound
called
<wx._core.KeyEvent object at 0x0385B340>

Going back to my original application, I find it also captures this. The function keys also cause the OnKey() function to be called. However, no amount of pressing the keys I want to catch (the "regular" keys, such as alpha-numerics, punctuation, ENTER, and TAB, and so on) result in a call to OnKey().

My intent (if it matters) is simply to store the key presses into a queue for processing elsewhere in my application.

What am I missing here? How can I capture those key-presses?

Asked By: paxdiablo

||

Answers:

Interesting. Further investigation turned up a question on the wxPython discussion board. The upshot appears to be that there are subtle differences between panel handling on the different platforms for native widgets.

The solution is to use a window rather than a panel and I can confirm that this works, although I have a small amount of work to do to get the window background coloring the same as all the other controls.

However, since it now successfully intercepts the entire "ASCII" part of the keyboard (and other things like cursor movement keys and such), I think this is probably all that’s needed.

Answered By: paxdiablo

I have a small contribution – I found that pressing some keys (eg cursor up, but F1 returned 0 correctly) caused the panel to lose focus. Clicking in it to regain focus and it responded again. The first line is from initialisation.

    self.panel.Bind(wx.EVT_CHAR,self.onkey)
    
  def onkey(self,event):
    code = event.GetUnicodeKey()
    print(code)
Answered By: hamiljf
Categories: questions Tags: , , ,
Answers are sorted by their score. The answer accepted by the question owner as the best is marked with
at the top-right corner.