Correct way to capture keypresses and arrows in particular?

Hi all,

My UI has this layout

Menu Bar
Panel 1: some buttons and radio buttons
Panel 2: An image in a StaticBitmap; then a vertical BoxSizer containing some additional buttons, dropdowns, and a text box
Panel 3: More buttons

The user can draw various specific markups on the image using the mouse. I would also like for certain keypresses to be processed by the image panel. This has limited success so far. When initialized, focus is set on the panel containing the StaticBitmap. The panel’s event handler reads thus

def OnKeyDown(self, event):
        
        if self.inWindow:  # flag set True when mouse enters StaticBitmap, False when mouse exits
            print("key down", event.GetKeyCode())
            
            if self.state == "box":
                if self.currentBox.state == "rotating":
                    if event.GetKeyCode() == wx.WXK_LEFT:
                        self.currentBox.Rotate(-Box.DELTA_ANGLE)
                    elif event.GetKeyCode() == wx.WKX_RIGHT:
                        self.currentBox.Rotate(Box.DELTA_ANGLE)
        
        event.Skip()

When various keys are pressed, I get appropriate output “key down 65”, etc. … until I hit an arrow key. Then the buttons and/or text box gets the focus, and no amount of mouse-clicking or keystroking can return the focus to the panel. As an experiment, I tried disabling keyboard focus on each button and text box; no joy. I also tried splitting the middle panel into two separate panels. No joy and it looked uglier.

Any advice on how to do this right?

Thanks,

Hi Jeff,

The panel focus mechanism is a bit complicated than other windows. When you click the panel, it actually moves the focus to the child window if exists. Note that StaticBitmap never gets focus, but other controls such as buttons and text controls do.
If you want to get the key event on the panel, you should use SetFocusIgnoringChildren to move focus to the panel in mouse handlers such as EVT_LEFT_DOWN.

https://wxpython.org/Phoenix/docs/html/wx.Panel.html

Thanks! I will try it and report back.

@komoto48g : No change in behavior. Specifically, if I mouse into the bitmap and hit non-arrow keys, I get the keystroke action. That’s true whether SetFocus() or SetFocusIgnoringChildren() is called. As soon as I hit an arrow key, the focus shifts to the TextBox control. That’s also true whether SetFocus() or SetFocusIgnoringChildren() is called.

What is different about the arrow keys as opposed to other keys? And should I be using EVT_CHAR_HOOK instead?

Yes, you should use EVT_CHAR_HOOK.
(Sorry that I didn’t read well that you are using arrow keys…)

Keys such as [alt], [Tab], [Left | Right | Up | Down] are called navigation keys.
For example, pressing [alt] triggers EVT_NAVIGATION_KEY instead of EVT_KEY_DOWN and will move the focus to the menubar. (wx.NavigationKeyEvent — wxPython Phoenix 4.1.2a1 documentation)
If you want to get those keys, bind EVT_CHAR_HOOK to the Panel. If you don’t skip the event, it will not be forwarded to the parent frame and no navigation will occur.

1 Like

Thanks,
This was the first I’ve seen of EVT_CHAR_HOOK. It did the trick. Now all I need is a way of ignoring ALT- to allow using the menus.
Ray

well, pull up an EventFilter for the object with :sunglasses:

        if evt.GetEventType() == self.char_hook and\
                evt.GetKeyCode() == wx.WXK_ALT:
            return self.Event_Ignore
        else:
            return self.Event_Skip