Can't seem to capture keyboard events

If someone could show me what I'm doing wrong here, I'd be very grateful. The Demo keyboard events program runs fine. Here's my code snippet:

class MyPanel(wx.Panel):

    def __init__(self, parent):

       wx.Panel.__init__(self, parent, -1,
                            wx.DefaultPosition,
                            wx.DefaultSize,
                            wx.WANTS_CHARS |
                            wx.FULL_REPAINT_ON_RESIZE
                            )

       self.Bind(wx.EVT_CHAR, self.OnTestEvent)
       self.Bind(wx.EVT_KEY_DOWN, self.OnTestEvent)
       self.Bind(wx.EVT_KEY_UP, self.OnTestEvent)

    def OnTestEvent(self, event):
       print "Event:", event
       event.Skip()

This is all embedded in a wx.Frame. The 'OnTestEvent routine just never gets called. The only difference with the demo that I can see is that it uses a wx.Window instead of a wx.Panel. I've also tried the same on the wx.Frame.

Thanks for any help,
Michael

Hello!

Just a wild guess. Can it be a "not-in-focus" issue? What if you do mouse
click (or SetFocus() ) on your panel?

    Vladimir Ignatov

···

----- Original Message -----
From: "Michael Hipp" <Michael@Hipp.com>
To: <wxPython-users@lists.wxwidgets.org>
Sent: Monday, November 08, 2004 6:53 PM
Subject: [wxPython-users] Can't seem to capture keyboard events

If someone could show me what I'm doing wrong here, I'd be very
grateful. The Demo keyboard events program runs fine. Here's my code
snippet:

class MyPanel(wx.Panel):

    def __init__(self, parent):

       wx.Panel.__init__(self, parent, -1,
                            wx.DefaultPosition,
                            wx.DefaultSize,
                            wx.WANTS_CHARS |
                            wx.FULL_REPAINT_ON_RESIZE
                            )

       self.Bind(wx.EVT_CHAR, self.OnTestEvent)
       self.Bind(wx.EVT_KEY_DOWN, self.OnTestEvent)
       self.Bind(wx.EVT_KEY_UP, self.OnTestEvent)

    def OnTestEvent(self, event):
       print "Event:", event
       event.Skip()

This is all embedded in a wx.Frame. The 'OnTestEvent routine just never
gets called. The only difference with the demo that I can see is that it
uses a wx.Window instead of a wx.Panel. I've also tried the same on the
wx.Frame.

Thanks for any help,
Michael

I've clicked every place on the panel, in every control, on the menu bar, on the titlebar, the status bar, the empty areas of the panel. All to no avail. My OnTestEvent() routine never gets called. But thanks for the thought.

Michael

Vladimir Ignatov wrote:

···

Hello!

Just a wild guess. Can it be a "not-in-focus" issue? What if you do mouse
click (or SetFocus() ) on your panel?

    Vladimir Ignatov

----- Original Message ----- From: "Michael Hipp" <Michael@Hipp.com>
To: <wxPython-users@lists.wxwidgets.org>
Sent: Monday, November 08, 2004 6:53 PM
Subject: [wxPython-users] Can't seem to capture keyboard events

If someone could show me what I'm doing wrong here, I'd be very
grateful. The Demo keyboard events program runs fine. Here's my code
snippet:

class MyPanel(wx.Panel):

   def __init__(self, parent):

      wx.Panel.__init__(self, parent, -1,
                           wx.DefaultPosition,
                           wx.DefaultSize,
                           wx.WANTS_CHARS |
                           wx.FULL_REPAINT_ON_RESIZE
                           )

      self.Bind(wx.EVT_CHAR, self.OnTestEvent)
      self.Bind(wx.EVT_KEY_DOWN, self.OnTestEvent)
      self.Bind(wx.EVT_KEY_UP, self.OnTestEvent)

   def OnTestEvent(self, event):
      print "Event:", event
      event.Skip()

This is all embedded in a wx.Frame. The 'OnTestEvent routine just never
gets called. The only difference with the demo that I can see is that it
uses a wx.Window instead of a wx.Panel. I've also tried the same on the
wx.Frame.

Thanks for any help,
Michael

---------------------------------------------------------------------
To unsubscribe, e-mail: wxPython-users-unsubscribe@lists.wxwidgets.org
For additional commands, e-mail: wxPython-users-help@lists.wxwidgets.org

Michael Hipp wrote:

I've clicked every place on the panel, in every control, on the menu bar, on the titlebar, the status bar, the empty areas of the panel. All to no avail. My OnTestEvent() routine never gets called. But thanks for the thought.

Put your code into a small complete running sample. If you don't find the problem doing that, post it here, and we can check it out.

-Chris

···

--
Christopher Barker, Ph.D.
Oceanographer
                                         
NOAA/OR&R/HAZMAT (206) 526-6959 voice
7600 Sand Point Way NE (206) 526-6329 fax
Seattle, WA 98115 (206) 526-6317 main reception

Chris.Barker@noaa.gov

Chris Barker wrote:

Michael Hipp wrote:

I've clicked every place on the panel, in every control, on the menu bar, on the titlebar, the status bar, the empty areas of the panel. All to no avail. My OnTestEvent() routine never gets called. But thanks for the thought.

Put your code into a small complete running sample. If you don't find the problem doing that, post it here, and we can check it out.

import wx

class MyFrame(wx.Frame):
    def __init__(self, parent):
       wx.Frame.__init__(self, parent, -1, "Frame",
                wx.DefaultPosition,
                wx.DefaultSize,
                wx.WANTS_CHARS |
                wx.DEFAULT_FRAME_STYLE
                )

       # Uncomment this line to BREAK IT
       #panel = wx.Panel(self, -1)

       self.Bind(wx.EVT_CHAR, self.OnKeyEvent)

       self.Show(True)

    def OnKeyEvent(self, event):
       print "KeyEvent:", event
       event.Skip()

class MyApp(wx.App):
    def OnInit(self):
       frame = MyFrame(None)
       self.SetTopWindow(frame)
       return True

app = MyApp(0)
app.MainLoop()

This example as written works. Uncomment the panel line and it stops giving the wx.EVT_CHAR event. I've tried giving the panel wx.WANTS_CHARS style and binding the event to the panel but no go.

The panel appears to be an impenetrable barrier to key events. Is there a workaround?

Thanks for any help you can offer,
Michael Hipp

Michael Hipp wrote:

This example as written works. Uncomment the panel line and it stops

Oddly, it doesn't work for me as is. But it does if you do this:

       # Uncomment this line to BREAK IT
       panel = wx.Panel(self, -1)
       panel.Bind(wx.EVT_CHAR, self.OnKeyEvent)

       #self.Bind(wx.EVT_CHAR, self.OnKeyEvent)

You want to bind the Event to the panel, not the frame, when you put the panel there.

tested with wxGTK 2.5.1 and 2.5.3p

-Chris

···

--
Christopher Barker, Ph.D.
Oceanographer
                                         
NOAA/OR&R/HAZMAT (206) 526-6959 voice
7600 Sand Point Way NE (206) 526-6329 fax
Seattle, WA 98115 (206) 526-6317 main reception

Chris.Barker@noaa.gov

Michael,

Check your initial code carefully. Appears you do some typo or such. I make
a "full" version of your first example and it works fine for me (wxPython
2.5.2.9, Windows 2000):

···

----------------------
import wx

class MyPanel(wx.Panel):

    def __init__(self, parent):

       wx.Panel.__init__(self, parent, -1,
                            wx.DefaultPosition,
                            wx.DefaultSize,
                            wx.WANTS_CHARS |
                            wx.FULL_REPAINT_ON_RESIZE
                            )

       self.Bind(wx.EVT_CHAR, self.OnTestEvent)
       self.Bind(wx.EVT_KEY_DOWN, self.OnTestEvent)
       self.Bind(wx.EVT_KEY_UP, self.OnTestEvent)

    def OnTestEvent(self, event):
       print "Event:", event
       event.Skip()

app = wx.PySimpleApp()
w = wx.Frame( None, -1, 'ttt' )
MyPanel( w )
w.Show()
app.MainLoop()
------------------------

   Vladimir Ignatov

Hi

Oddly, it doesn't work for me as is. But it does if you do this:
[...]
You want to bind the Event to the panel, not the frame, when you put the
panel there.

The problem is, when you have a more complicated design.

For example the following:

class MyFrame(wx.Frame):
    def __init__(self, parent):
        wx.Frame.__init__(self, parent, -1, "Frame",
                wx.DefaultPosition,
                wx.DefaultSize,
                wx.WANTS_CHARS |
                wx.DEFAULT_FRAME_STYLE
                )

        panel = wx.Panel(self, -1)
        panel1 = wx.Panel(panel, -1)

Here you have to the key event to panel1, cause panel or the frame never
receive the event.

And with a sizer:

class MyFrame(wx.Frame):
    def __init__(self, parent):
        wx.Frame.__init__(self, parent, -1, "Frame",
                wx.DefaultPosition,
                wx.DefaultSize,
                wx.WANTS_CHARS |
                wx.DEFAULT_FRAME_STYLE
                )

        panel = wx.Panel(self, -1)
        sizer = wx.BoxSizer(wx.HORIZONTAL)
        panel1 = wx.Panel(panel, -1)
        panel2 = wx.Panel(panel, -1)
        sizer.Add(panel1)
        sizer.Add(panel2)
        panel.SetAutoLayout(True)
        panel.SetSizer(sizer)
        panel.Layout()

Now you have to bind the event to the panel, that has the focus. But in
most cases the focus can change, so you have to bind the event to both
panels.

It seems to me, that only windows, that have the focus, can receive key
events. And if you have a panel on a frame, than the frame can't get the
focus. But if that is true - why does a menubar always get the key
events?

cu boesi

···

Am 09.11.2004 01:32:33 schrieb Chris Barker:
--
--==SECURITY ALERT==-- #1671 : icq-intern
Your Computer Is Currently Broadcasting An #73628288 : icq-extern
Internet IP Address. With This Address, boesi111 : aim
Someone Can Begin Attacking Your Computer. i171 : reallife

Chris Barker wrote:

Michael Hipp wrote:

This example as written works. Uncomment the panel line and it stops

You want to bind the Event to the panel, not the frame, when you put the panel there.

Thanks Chris, Vladimir, Alexander for all your help. Here is a slightly more complicated example. The example works as written but breaks when the TextCtrl is enabled. Can someone show me how to make it work with the text control enabled?

import wx

class MyPanel(wx.Panel):
    def __init__(self, parent):
       wx.Panel.__init__(self, parent)

       # *** Uncomment this line to BREAK IT
       #self.myText = wx.TextCtrl(self, -1, "")

class MyFrame(wx.Frame):
    def __init__(self, parent):
       wx.Frame.__init__(self, parent, -1, "Frame",
                wx.DefaultPosition,
                wx.DefaultSize,
                wx.WANTS_CHARS |
                wx.DEFAULT_FRAME_STYLE
                )

       panel = MyPanel(self)
       panel.Bind(wx.EVT_CHAR, self.OnKeyEvent)

       self.Show(True)

    def OnKeyEvent(self, event):
       print "KeyEvent:", event
       event.Skip()

class MyApp(wx.App):
    def OnInit(self):
       frame = MyFrame(None)
       self.SetTopWindow(frame)
       return True

app = MyApp(0)
app.MainLoop()

I'm on W2k Pro SP4, wxPython 2.5, Python 2.3.

Thanks,
Michael

Hi

Thanks Chris, Vladimir, Alexander for all your help. Here is a slightly
more complicated example. The example works as written but breaks when
the TextCtrl is enabled. Can someone show me how to make it work with
the text control enabled?

It's the same problem, I have described above - bind the event to the
TextCtrl and it works...
As soon as some widget is on a panel, the panel doesn't get a key event
anymore. When you destroy the widget, the panel gets the key event again.

Try the following class:

class MyPanel(wx.Panel):
    def __init__(self, parent):
        wx.Panel.__init__(self, parent)

        # *** Uncomment this line to BREAK IT
        self.myText = wx.TextCtrl(self, -1, "")
        self.Bind(wx.EVT_CHAR, self.OnKeyEventPanel)
        self.myText.Bind(wx.EVT_CHAR, self.OnKeyEventText)

    def OnKeyEventPanel(self, event):
        print "Panel KeyEvent:", event
        event.Skip()

    def OnKeyEventText(self, event):
        print "Text KeyEvent:", event
        self.myText.Destroy()

It would make me really happy, if someone knows, how to receive key
events by a parent panel / frame.
        
cu boesi

···

Am 09.11.2004 15:15:43 schrieb Michael Hipp:
--
Ein Wunder muss heute schon ganz schoen #1671 : icq-intern
wundervoll sein um ein Wunder zu sein, #73628288 : icq-extern
sonst wuerde man sich ja gar nicht mehr wundern boesi111 : aim
                 .-==Prof. Dr. Harald Lesch==-. i171 : reallife

Alexander 'boesi' Bösecke wrote:

Hi

It's the same problem, I have described above - bind the event to the
TextCtrl and it works...
As soon as some widget is on a panel, the panel doesn't get a key event
anymore. When you destroy the widget, the panel gets the key event again.

Try the following class:

Thank you, thank you, ever so thank you! It works.

It would make me really happy, if someone knows, how to receive key
events by a parent panel / frame.

Yes. That would seem more elegant than a very long list of "Bind" calls for a populous panel, but in the meantime I can get on with my project.

Thanks Alexander (and Vladimir and Chris too).

Michael Hipp

···

Am 09.11.2004 15:15:43 schrieb Michael Hipp:

Michael Hipp wrote:

Yes. That would seem more elegant than a very long list of "Bind" calls

I think what you want is an Accelerator table, not trying to capture Key events. Capturing key events is for Window-specific behavior.

Look in the docs for wxAcceleratorTable and there have been a number of discussions on this list.

Just a note: It is always helpful to state the larger problem you are trying to solve:

"I have a panel with lots of controls, and want to capture a key stroke regardless of which control has focus, to give a command"

rather than:

"How do I bind key events to a panel?"

Then we can help you find the solution to your real problem.

-Chris

···

--
Christopher Barker, Ph.D.
Oceanographer
                                         
NOAA/OR&R/HAZMAT (206) 526-6959 voice
7600 Sand Point Way NE (206) 526-6329 fax
Seattle, WA 98115 (206) 526-6317 main reception

Chris.Barker@noaa.gov

Chris Barker wrote:

I think what you want is an Accelerator table, not trying to capture Key events. Capturing key events is for Window-specific behavior.

Actually, what I'm doing is for control-specific behavior (e.g. The Plus key does something different in TextCtrl1 than in TextCtrl2). So the key events is probably the best bet (if I'm correctly understanding what I read about wxAcceleratorTable).

Just a note: It is always helpful to state the larger problem you are trying to solve:

"I have a panel with lots of controls, and want to capture a key stroke regardless of which control has focus, to give a command"

rather than:

"How do I bind key events to a panel?"

True. And good to remember. Unfortunately the syndrome of being "neck deep in alligators" is too often the case here :slight_smile:

Again, thanks.

Michael

I have an application that works great on Windows, but now needs to be able
to work on a Mac as well. The Windows app runs in the system tray and then
pops up a window when an event happens. Mac's don't have a system tray, so
I need to do something else. Is it possible to create a menubar without
tying it to a frame? Or is there a different way to go about this when
programming on a Mac?

The Mac is running Jaguar (OS X 10.2) with MacPython 2.3.3 and wxPython
2.5.2.8.

cheers,
Anton

Michael Hipp wrote:

Actually, what I'm doing is for control-specific behavior (e.g. The Plus key does something different in TextCtrl1 than in TextCtrl2). So the key events is probably the best bet (if I'm correctly understanding what I read about wxAcceleratorTable).

Yup, Key Events is probably what you want. Now I'm confused. I thought you wanted to capture key events on a Panel that a bunch of controls are on. Maybe that was someone else.

-Chris

···

--
Christopher Barker, Ph.D.
Oceanographer
                                         
NOAA/OR&R/HAZMAT (206) 526-6959 voice
7600 Sand Point Way NE (206) 526-6329 fax
Seattle, WA 98115 (206) 526-6317 main reception

Chris.Barker@noaa.gov

Chris Barker wrote:

Michael Hipp wrote:

Actually, what I'm doing is for control-specific behavior (e.g. The Plus key does something different in TextCtrl1 than in TextCtrl2). So the key events is probably the best bet (if I'm correctly understanding what I read about wxAcceleratorTable).

Yup, Key Events is probably what you want. Now I'm confused. I thought you wanted to capture key events on a Panel that a bunch of controls are on. Maybe that was someone else.

Naw, that was probably me. I was working from the concept I gleaned looking at the KeyEvents in demo.py, where it catches everything indiscriminately in a largish window. So I erroneously presumed that the way to catch keys is to bind it to the panel and sort them out in the event method.

I think I now understand that catching key events is more of a "bottom-up" approach.

Michael

Michael Hipp wrote:

This is all embedded in a wx.Frame. The 'OnTestEvent routine just never gets called. The only difference with the demo that I can see is that it uses a wx.Window instead of a wx.Panel. I've also tried the same on the wx.Frame.

I know this has been resolved already but just for the record if a Panel has children it will always try to pass the focus to one of them whenever it gets the focus.

···

--
Robin Dunn
Software Craftsman
http://wxPython.org Java give you jitters? Relax with wxPython!

Anton Visser wrote:

I have an application that works great on Windows, but now needs to be able
to work on a Mac as well. The Windows app runs in the system tray and then
pops up a window when an event happens. Mac's don't have a system tray, so
I need to do something else. Is it possible to create a menubar without
tying it to a frame? Or is there a different way to go about this when
programming on a Mac?

The Mac is running Jaguar (OS X 10.2) with MacPython 2.3.3 and wxPython
2.5.2.8.

Currently you need to create a frame that is hidden or located off screen. There has been some discussion over the last couple days about adding an wxApp::SetMenuBar that would do it without the frame and would be a no-op on the other platforms

···

--
Robin Dunn
Software Craftsman
http://wxPython.org Java give you jitters? Relax with wxPython!