Stumped: arrows/tab kills keyboard focus

I have a panel that should receive keyboard events. It works fine on OSX and GTK (Linux).

On Windows, it receives “normal” keyboard events (letter keys, number keys, etc.) If I type an arrow key or tab key, it loses focus and gives focus to a ListCtrl in another panel. If I enter an ENTER key, it does not receive the ENTER keypress (but does not change the focus). This is not the desired behavior – I need to process the arrow keys and enter keys on the panel that initially had the focus.

There may be an event I could trap here to see where these arrow/enter/tab keypresses are going to, but I can’t spot it.

How can I either prevent this grabbing of my keystrokes or intercept it?

Attached is a simple reproduction of the problem. On OSX, when this is run, you can enter “normal” keys or arrow/tab/enter and get console confirmation that the panel’s event got them. On Windows, you can enter “normal” keys and get the same confirmation. Enter keys vanish. Tab/Arrow keys vanish and then the focus magically moves to the listctrl (you can confirm this by arrowing up/down in the list).

Thanks for any help – I’m stumped here.

focus.py (1.15 KB)

Digging further into archives, I found a message here that suggests adding “style=0” to my panel initialization should solve the problem, and it does. (I’m not sure what I’m overriding there–any tips would be helpful).

HOWEVER, this doesn’t actually solve my real problem – in the real program, the panel is in a MultiSplitterWindow and, when my simple test case code is updated to reflect this, we’re back to the same problem: “normal” keys and “movement keys” both are caught in OSX, but only “normal” keys in Windows and the focus is moved to the listctrl by arrow/tab keys.

Attaching update reproducible problem code, now with “style=0” on panel but in a MultiSplitterWindow.

Thanks!

  • j.

focus.py (1.21 KB)

···

On Wednesday, June 6, 2012 5:02:26 PM UTC-7, Joel Burton wrote:

I have a panel that should receive keyboard events. It works fine on OSX and GTK (Linux).

On Windows, it receives “normal” keyboard events (letter keys, number keys, etc.) If I type an arrow key or tab key, it loses focus and gives focus to a ListCtrl in another panel. If I enter an ENTER key, it does not receive the ENTER keypress (but does not change the focus). This is not the desired behavior – I need to process the arrow keys and enter keys on the panel that initially had the focus.

There may be an event I could trap here to see where these arrow/enter/tab keypresses are going to, but I can’t spot it.

How can I either prevent this grabbing of my keystrokes or intercept it?

Attached is a simple reproduction of the problem. On OSX, when this is run, you can enter “normal” keys or arrow/tab/enter and get console confirmation that the panel’s event got them. On Windows, you can enter “normal” keys and get the same confirmation. Enter keys vanish. Tab/Arrow keys vanish and then the focus magically moves to the listctrl (you can confirm this by arrowing up/down in the list).

Thanks for any help – I’m stumped here.

Digging further into archives, I found a message here that suggests
adding "style=0" to my panel initialization should solve the problem,
and it does. (I'm not sure what I'm overriding there--any tips would be
helpful).

The default style for panels is wx.TAB_TRAVERSAL, so passing style=0 turns that off.

HOWEVER, this doesn't actually solve my real problem -- in the real
program, the panel is in a MultiSplitterWindow and, when my simple test
case code is updated to reflect this, we're back to the same problem:
"normal" keys and "movement keys" both are caught in OSX, but only
"normal" keys in Windows and the focus is moved to the listctrl by
arrow/tab keys.

On Windows wxWidgets needs to process things like arrow keys a little differently but there is an additional style that can be used to get normal char events for them. (I think it also affects the production of key-down events too.) Try using style=wx.WANTS_CHARS.

You may also want to switch to a wx.Window instead of a wx.Panel. Once you turn off tab traversal and do not have any child widgets, then there really isn't a whole lot of difference between them. However there may still be some navigation related features that could show up and effect the behaviors you want.

Finally, MultiSplitterWindow is also a wx.Panel, so it will participate in navigation and such and may also get in the way of what you are wanting. I see that it is always adding the wx.TAB_TRAVERSAL style before calling the base class __init__ so you may need to turn it off again after construction.

···

On 6/6/12 5:30 PM, Joel Burton wrote:

--
Robin Dunn
Software Craftsman
http://wxPython.org

Robin – I appreciate your help. One small question remains; read down.

HOWEVER, this doesn’t actually solve my real problem – in the real

program, the panel is in a MultiSplitterWindow and, when my simple test

case code is updated to reflect this, we’re back to the same problem:

“normal” keys and “movement keys” both are caught in OSX, but only

“normal” keys in Windows and the focus is moved to the listctrl by

arrow/tab keys.

On Windows wxWidgets needs to process things like arrow keys a little
differently but there is an additional style that can be used to get
normal char events for them. (I think it also affects the production of
key-down events too.) Try using style=wx.WANTS_CHARS.

Adding wx.WANTS_CHARS to the style of my inner panel (the one that does, in fact, want the chars) solves the problem. Thanks!

You may also want to switch to a wx.Window instead of a wx.Panel. Once
you turn off tab traversal and do not have any child widgets, then there
really isn’t a whole lot of difference between them. However there may
still be some navigation related features that could show up and effect
the behaviors you want.

Also changed this; thanks. Early on, I found several good explanations of wx.Frame v wx.Panel, but wasn’t clear on Panel versus Window.

Finally, MultiSplitterWindow is also a wx.Panel, so it will participate
in navigation and such and may also get in the way of what you are
wanting. I see that it is always adding the wx.TAB_TRAVERSAL style
before calling the base class init so you may need to turn it off
again after construction.

Given that wx.WANTS_CHARS solves this problem. I apparently don’t need to turn off the TAB_TRAVERSAL on the splitter.

But I’m curious how I could do so best I can make it work by wholesale copying the original splitter.py MultiSplitterWindow init into a subclassed NonTraversingSplitterWindow and commenting out the line that always adds TAB_TRAVERSAL. That worked but it’s pretty ugly copying and pasting the entire init method into the subclass. You make it sound like I can adjust the style after construction, but I don’t see how. Any pointers?

Thanks!

  • j.
···

On Thursday, June 7, 2012 8:52:51 AM UTC-7, Robin Dunn wrote:

On 6/6/12 5:30 PM, Joel Burton wrote:

See wx.Window.SetWindowStyleFlag. Not all styles can be changed after construction, but I believe that wx.WANTS_CHARS can.

···

On 6/7/12 11:16 AM, Joel Burton wrote:

    Finally, MultiSplitterWindow is also a wx.Panel, so it will participate
    in navigation and such and may also get in the way of what you are
    wanting. I see that it is always adding the wx.TAB_TRAVERSAL style
    before calling the base class __init__ so you may need to turn it off
    again after construction.

Given that wx.WANTS_CHARS solves this problem. I apparently don't need
to turn off the TAB_TRAVERSAL on the splitter.

But I'm curious how I could do so best I can make it work by wholesale
copying the original splitter.py MultiSplitterWindow __init__ into a
subclassed NonTraversingSplitterWindow and commenting out the line that
always adds TAB_TRAVERSAL. That worked but it's pretty ugly copying and
pasting the entire __init__ method into the subclass. You make it sound
like I can adjust the style after construction, but I don't see how. Any
pointers?

--
Robin Dunn
Software Craftsman
http://wxPython.org

Thanks, Robin! I appreciate your extra help here.

  • j.
···

On Thursday, June 7, 2012 3:57:53 PM UTC-7, Robin Dunn wrote:

On 6/7/12 11:16 AM, Joel Burton wrote:

Finally, MultiSplitterWindow is also a wx.Panel, so it will participate
in navigation and such and may also get in the way of what you are
wanting. I see that it is always adding the wx.TAB_TRAVERSAL style
before calling the base class __init__ so you may need to turn it off
again after construction.

Given that wx.WANTS_CHARS solves this problem. I apparently don’t need

to turn off the TAB_TRAVERSAL on the splitter.

But I’m curious how I could do so best I can make it work by wholesale

copying the original splitter.py MultiSplitterWindow init into a

subclassed NonTraversingSplitterWindow and commenting out the line that

always adds TAB_TRAVERSAL. That worked but it’s pretty ugly copying and

pasting the entire init method into the subclass. You make it sound

like I can adjust the style after construction, but I don’t see how. Any

pointers?

See wx.Window.SetWindowStyleFlag. Not all styles can be changed after
construction, but I believe that wx.WANTS_CHARS can.


Robin Dunn

Software Craftsman

http://wxPython.org