How to know what event IDs to use in menu?

I've been using wxPython for probably 5 years now, and I'm
afraid I still don't "get" event IDs.

For example, I don't understand how one knows what event IDs to
use when doing things like binding handlers to menu items.
Here's the example from the tutorial:

    from wxPython.wx import *
    
    ID_ABOUT = 101
    ID_EXIT = 102
    
    class MyFrame(wxFrame):
        def __init__(self, parent, ID, title):
            wxFrame.__init__(self, parent, ID, title,
                             wxDefaultPosition, wxSize(200, 150))
            self.CreateStatusBar()
            self.SetStatusText("This is the statusbar")
    
            menu = wxMenu()
            menu.Append(ID_ABOUT, "&About",
                        "More information about this program")
            menu.AppendSeparator()
            menu.Append(ID_EXIT, "E&xit", "Terminate the program")
    
            menuBar = wxMenuBar()
            menuBar.Append(menu, "&File");
    
            self.SetMenuBar(menuBar)

            EVT_MENU(self, ID_ABOUT, self.OnAbout)
            EVT_MENU(self, ID_EXIT, self.TimeToQuit)

Where do the values 101 and 102 come from? How are they
different from wx.ID_ABOUT and wx.ID_EXIT. When would you use
wx.ID_ABOUT or wx.ID_EXIT?

When pulling numbers like 101 and 102 out of the air, how do
you know they don't conflict with event IDs wx is using for
something else? Is the event "number space" considered to be
global?

Why should one even have to pull a bunch of arbitrary numbers
out of the air in order to connect a handler to a menu? Why
not just tell the menu what hanlder to call?

  menu.Append("&About","More information about this program",handler=self.OnAbout)

If oen were to subclass wx.Menu to do that, what are the rules
for generating event IDs?

···

--
Grant Edwards grante Yow! Can I have an IMPULSE
                                  at ITEM instead?
                               visi.com

Well, my first attempt to "fix" the Menu API didn't work:

    class MyMenu(wx.Menu):
        def __init__(self, *argv):
            wx.Menu.__init__(self, *argv)
            self.__nextEventId = 101
        def Append(self, *argv, **kwargs):
            if 'handler' in kwargs:
                handler = kwargs['handler']
                del kwargs['handler']
                r = wx.Menu.Append(self,self.__nextEventId,*argv,**kwargs)
                self.Bind(wx.EVT_MENU, handler, id=self.__nextEventId)
                self.__nextEventId += 1
                return r
            else:
                return wx.Menu.Append(self,*argv,**kwargs)
    
Apparently the wx.Menu.Bind() method doesn't do what it I need
it to do? What _does_ it do?

···

On 2007-04-23, Grant Edwards <grante@visi.com> wrote:

I've been using wxPython for probably 5 years now, and I'm
afraid I still don't "get" event IDs.

Why should one even have to pull a bunch of arbitrary numbers
out of the air in order to connect a handler to a menu? Why
not just tell the menu what hanlder to call?

  menu.Append("&About","More information about this program",handler=self.OnAbout)

--
Grant Edwards grante Yow! My LESLIE GORE record
                                  at is BROKEN ...
                               visi.com

Hi Grant,

For the reasons you mention about creating possible conflicts with
ID's I have started using wx.NewID():

        ID = wx.NewId()
        menu1.Append(ID, '&Open', 'Open')
        self.Bind(wx.EVT_MENU, self.OnFileOpen, id=ID)

        menu1.AppendSeparator()

        ID = wx.NewId()
        menu1.Append(ID, '&Save', 'Save')
        self.Bind(wx.EVT_MENU, self.OnFileSave, id=ID)

There are some constants wx.ID_LOWEST and wx.ID_HIGHEST that I read
about in "WxPython In Action" (pg 42-43) that you can also use to
prevent conflicts.

Monday, April 23, 2007, 12:13:16 PM, you wrote:

···

I've been using wxPython for probably 5 years now, and I'm
afraid I still don't "get" event IDs.

For example, I don't understand how one knows what event IDs to
use when doing things like binding handlers to menu items.
Here's the example from the tutorial:

    from wxPython.wx import *
    
    ID_ABOUT = 101
    ID_EXIT = 102
    
    class MyFrame(wxFrame):
        def __init__(self, parent, ID, title):
            wxFrame.__init__(self, parent, ID, title,
                             wxDefaultPosition, wxSize(200, 150))
            self.CreateStatusBar()
            self.SetStatusText("This is the statusbar")
    
            menu = wxMenu()
            menu.Append(ID_ABOUT, "&About",
                        "More information about this program")
            menu.AppendSeparator()
            menu.Append(ID_EXIT, "E&xit", "Terminate the program")
    
            menuBar = wxMenuBar()
            menuBar.Append(menu, "&File");
    
            self.SetMenuBar(menuBar)

            EVT_MENU(self, ID_ABOUT, self.OnAbout)
            EVT_MENU(self, ID_EXIT, self.TimeToQuit)

Where do the values 101 and 102 come from? How are they
different from wx.ID_ABOUT and wx.ID_EXIT. When would you use
wx.ID_ABOUT or wx.ID_EXIT?

When pulling numbers like 101 and 102 out of the air, how do
you know they don't conflict with event IDs wx is using for
something else? Is the event "number space" considered to be
global?

Why should one even have to pull a bunch of arbitrary numbers
out of the air in order to connect a handler to a menu? Why
not just tell the menu what hanlder to call?

  menu.Append("&About","More information about this program",handler=self.OnAbout)

If oen were to subclass wx.Menu to do that, what are the rules
for generating event IDs?

For the reasons you mention about creating possible conflicts with
ID's I have started using wx.NewID():

Better yet, don't use explicit IDs at all. (see the wxPython style guide
in the Wiki)

Menu items don't behave as well as everything else in this
regard, but you can do:

          item = menu1.Append(wx.ID_ANY, '&Open', 'Open')
# you do need to put SOMETHING in for an ID with menu items -- I use wx.ID_ANY, 'cause I think it says what I mean.

          self.Bind(wx.EVT_MENU, self.OnFileOpen, item)

# you can specify the object that the event comes from, rather than the
# ID, I think this is cleaner.

Yes, that's much cleaner. I haven't figured out how to use the
use the wx.Menu.Bind() method instead of the "parent" Frame's
Bind method. It seems to me that one ought to be telling the
Menu object what handler to call and not the parent Frame, but
that doesn't look like the way it's done.

Here's the example from the tutorial:

The tutorial is pretty old -- we've come up with cleaner ways to write
code since then!

And people like me should stop whining and submit patches to
the tutorial.

    ID_ABOUT = 101
    ID_EXIT = 102

This is the only exception to my "no explicit IDs" rule. It IS a good
idea to use pre-defined ids for standard items -- it lets wxMac put them
in the right place for that platform, for instance:

              menu.Append(wx.ID_ABOUT, "&About",
                          "More information about this program")

              menu.Append(wx.ID_EXIT, "E&xit", "Terminate the program")

Don't overwrite the wx-defined ones though!

Which appears to be what the example in the tutorial is doing,
since it's using the now-deprecated from wx import "*" form.

See the Wiki page about porting to OS-X for more info.

Thanks, I will.

···

On 2007-04-23, Christopher Barker <Chris.Barker@noaa.gov> wrote:

--
Grant Edwards grante Yow! I don't understand
                                  at the HUMOUR of the THREE
                               visi.com STOOGES!!

Hi Grant,

I think the reason for this is described on page 302 in "wxPython in Action".
It's done so that toolbar buttons can use the same handler as the menu
item.

···

I'm still fuzzy on why I have to call the parent Frame's Bind()
method rather than the menu object's bind method, but at least
I don't have to look at event IDs in my code. :wink: