Menu Accelerators: no key events

Is that by design? I would need the pressed shortcuts from menu (Ctrl-s
for example for Save) also as keyevents, but apparantly they are
consumed before. Any possibility to get them "through" to the key event
handler of a control?

I don’t understand. Normally the accelerator keys call the exact same method that the menu item does. Isn’t that what you want?

···

On Wed, Aug 4, 2010 at 5:18 PM, FranzSt franz.steinhaeusler@gmx.at wrote:

Is that by design? I would need the pressed shortcuts from menu (Ctrl-s

for example for Save) also as keyevents, but apparantly they are

consumed before. Any possibility to get them “through” to the key event

handler of a control?

Mike Driscoll

Blog: http://blog.pythonlibrary.org

Mike Driscoll wrote:

Is that by design? I would need the pressed shortcuts from menu (Ctrl-s
for example for Save) also as keyevents, but apparantly they are
consumed before. Any possibility to get them "through" to the key event
handler of a control?

I don't understand. Normally the accelerator keys call the exact same method
that the menu item does. Isn't that what you want?

I havent't described it accurately enough.

Take a frame or panel. If for example, ctrl-F2 is not bind to a menu
item, i will get the key event, otherwise not. The ctrl-F2 for save is
working. But I need the key events to record a macro. and therefore i
will catch ALL the events for the EVT_KEY_DOWN for example. And it
Ctrl-F2 is bind to a menu accelerator, no event will come to the
EVT_KEY_DOWN or EVT_CHAR handler.

···

On Wed, Aug 4, 2010 at 5:18 PM, FranzSt <franz.steinhaeusler@gmx.at> wrote:

GadgetSteve@live.co.uk wrote:

I think that you need to ensure that the menu handlers ALL call event.skip()
at the end of processing to ensure that they do get passed on. There may be
a way to ensure that your macro recording process gets them first - probably
something to do with the order of the creation/binding, etc., - you could
try making sure that your macro recording function is always bound before
any other bindings, (including creating the menus with key bindings). It
would then need to only record if the mode was set to recording and always
call event.skip() whether recorded or not. If that doesn't work on your
platform try making sure the binding is last.

Gadget/Steve

--
To unsubscribe, send email to wxPython-users+unsubscribe@googlegroups.com
or visit http://groups.google.com/group/wxPython-users?hl=en

Thank you for your answer. Appending a event.Skip() at the end of a
EVT_MENU function did not help. Maybe a small demo example could help.
It seems, the menu shortcuts or "accelerators" are consumed up.

I created a small sample for that question:

import wx

class MyFrame(wx.Frame):

    def __init__(self, parent, title):
        wx.Frame.__init__(self, parent, title=title)

        menuBar = wx.MenuBar()
        menu1 = wx.Menu()

        item = wx.MenuItem(menu1, 500, "&Save\tCtrl-S")
        menu1.AppendItem(item)

        menuBar.Append(menu1, "&Test")
        self.SetMenuBar(menuBar)

        self.Bind(wx.EVT_MENU, self.OnSave, id=500)

        panel = wx.Panel(self)

        self.Bind(wx.EVT_KEY_DOWN, self.OnKey)
        self.Bind(wx.EVT_CHAR, self.OnChar)
        panel.Bind(wx.EVT_KEY_DOWN, self.OnKey)
        panel.Bind(wx.EVT_CHAR, self.OnChar)

        panel.SetFocus()

    def OnSave(self, event):
        print "OnSave"
        event.Skip()

    def OnKey(self, event):
        print "Object: ", event.GetEventObject()
        print "OnKey - Keycode", event.GetKeyCode()
        event.Skip()

    def OnChar(self, event):
        print "Object: ", event.GetEventObject()
        print "OnChar - Keycode", event.GetKeyCode()
        event.Skip()

app = wx.App(0)
win = MyFrame(None, title="Small Menu Sample, wxPython Version: " + wx.VERSION_STRING)
win.Show()
app.MainLoop()

When I press CTRL+S using this script, I get the following output:

<output>

Object: <wx._windows.Panel; proxy of <Swig Object of type 'wxPanel *'
at 0x1d88360> >
OnKey - Keycode 308
OnSave
OnSave

</output>

It looks like the EVT_KEY_DOWN is fired first, then the EVT_MENU. The
EVT_CHAR is not fired. I'm using Python 2.5, wxPython 2.8.10.1 on
Windows XP.

···

On Aug 5, 5:20 am, FranzSt <franz.steinhaeus...@gmx.at> wrote:

I created a small sample for that question:

import wx

class MyFrame(wx.Frame):

def \_\_init\_\_\(self, parent, title\):
    wx\.Frame\.\_\_init\_\_\(self, parent, title=title\)

    menuBar = wx\.MenuBar\(\)
    menu1 = wx\.Menu\(\)

    item = wx\.MenuItem\(menu1, 500, &quot;&amp;Save\\tCtrl\-S&quot;\)
    menu1\.AppendItem\(item\)

    menuBar\.Append\(menu1, &quot;&amp;Test&quot;\)
    self\.SetMenuBar\(menuBar\)

    self\.Bind\(wx\.EVT\_MENU, self\.OnSave, id=500\)

    panel = wx\.Panel\(self\)

    self\.Bind\(wx\.EVT\_KEY\_DOWN, self\.OnKey\)
    self\.Bind\(wx\.EVT\_CHAR, self\.OnChar\)
    panel\.Bind\(wx\.EVT\_KEY\_DOWN, self\.OnKey\)
    panel\.Bind\(wx\.EVT\_CHAR, self\.OnChar\)

    panel\.SetFocus\(\)

def OnSave\(self, event\):
    print &quot;OnSave&quot;
    event\.Skip\(\)

def OnKey\(self, event\):
    print &quot;Object: &quot;, event\.GetEventObject\(\)
    print &quot;OnKey \- Keycode&quot;, event\.GetKeyCode\(\)
    event\.Skip\(\)

def OnChar\(self, event\):
    print &quot;Object: &quot;, event\.GetEventObject\(\)
    print &quot;OnChar \- Keycode&quot;, event\.GetKeyCode\(\)
    event\.Skip\(\)

app = wx.App(0)
win = MyFrame(None, title="Small Menu Sample, wxPython Version: " + wx.VERSION_STRING)
win.Show()
app.MainLoop()

-------------------
Mike Driscoll

Blog: http://blog.pythonlibrary.org

Mike Driscoll wrote:

When I press CTRL+S using this script, I get the following output:

<output>

Object: <wx._windows.Panel; proxy of <Swig Object of type 'wxPanel *'
at 0x1d88360> >
OnKey - Keycode 308
OnSave
OnSave

Really, I don't get a OnKey - KeyCode, when I press Ctrl-S, only one
"OnSave"

wxpy 2.8.10.1, (X)Ubuntu, karmic

Did you run it with windows?

</output>

It looks like the EVT_KEY_DOWN is fired first, then the EVT_MENU. The
EVT_CHAR is not fired. I'm using Python 2.5, wxPython 2.8.10.1 on
Windows XP.

Ah yes. See above. :wink:

There is some platform variability in how accelerators are triggered and consumed. So although it may be made to work on some platforms, if something is an accelerator you can not depend on being able to get key/char events for it. Perhaps a better idea would be to raise your level of abstraction a bit. Instead of recording key strokes for your macros you could instead record "commands" and have all the event handlers that are for recordable items be able to participate in the recording process.

Another option would be to override FilterEvent in a class derived from wx.App. When you call SetCallFilterEvent(True) then FIlterEvent will be called for all events before they are dispatched out to event handlers or allowed to be handled by the default wx or system handlers. Return -1 to allow the events to be dispatched normally. You will still probably not get key events for the accelerator keys, but at least your macro recording can all be dealt with in a centralized location.

···

On 8/4/10 10:11 PM, FranzSt wrote:

Mike Driscoll wrote:

On Wed, Aug 4, 2010 at 5:18 PM, FranzSt<franz.steinhaeusler@gmx.at> wrote:

Is that by design? I would need the pressed shortcuts from menu (Ctrl-s
for example for Save) also as keyevents, but apparantly they are
consumed before. Any possibility to get them "through" to the key event
handler of a control?

I don't understand. Normally the accelerator keys call the exact same method
that the menu item does. Isn't that what you want?

I havent't described it accurately enough.

Take a frame or panel. If for example, ctrl-F2 is not bind to a menu
item, i will get the key event, otherwise not. The ctrl-F2 for save is
working. But I need the key events to record a macro. and therefore i
will catch ALL the events for the EVT_KEY_DOWN for example. And it
Ctrl-F2 is bind to a menu accelerator, no event will come to the
EVT_KEY_DOWN or EVT_CHAR handler.

--
Robin Dunn
Software Craftsman

Robin Dunn wrote:

There is some platform variability in how accelerators are triggered and
consumed. So although it may be made to work on some platforms, if
something is an accelerator you can not depend on being able to get
key/char events for it. Perhaps a better idea would be to raise your
level of abstraction a bit. Instead of recording key strokes for your
macros you could instead record "commands" and have all the event
handlers that are for recordable items be able to participate in the
recording process.

Another option would be to override FilterEvent in a class derived from
wx.App. When you call SetCallFilterEvent(True) then FIlterEvent will be
called for all events before they are dispatched out to event handlers
or allowed to be handled by the default wx or system handlers. Return
-1 to allow the events to be dispatched normally. You will still
probably not get key events for the accelerator keys, but at least your
macro recording can all be dealt with in a centralized location.

Hmm, my macro recording work alredy except the menu accelerators.

You were right, with FilterEvents I still get no menu accelerator
events. So either a limited Macro functionality or as you suggested,
another concept. But that is not worth the expenditure for me. I
surely had to change a lot in the app otherwise.

I don't understand why gtk is so greedy and do not let pass the events
as in windows. :wink: All the same...

GadgetSteve@live.co.uk wrote:

Alternately you could modify the handlers for each of your menu items to
check if macros were being recorded and if so record the event in the macro
in some format, this would have the nice side effect of including in your
macro menu selections made by mouse as well as those by keyboard
accelerator. You would have to add wrappers for some standard event
handlers as well.

Gadget/Steve

Thank you Steve, that ist an interesting idea.