How to know what event IDs to use in menu?

7stud bbxx789_05ss at yahoo.com
Tue Apr 24 19:51:56 PDT 2007


> I don't understand how one knows what event IDs to
> use when doing things like binding handlers to menu items

It's just like deciding which variable names to use in your 
programs.  An ID is an identifier just like a variable name.

>ID_ABOUT = 101
>ID_EXIT  = 102
>Where do the values 101 and 102 come from? 

They are someone's random integer values that will
serve as identifiers.

>How are they
>different from wx.ID_ABOUT and wx.ID_EXIT

ID_ABOUT and ID_EXIT are just some made up variable 
names in someone's program, and they are assigned 
some random integer values.  On the other hand wx.ID_ABOUT
and wx.ID_EXIT are some variable names defined in the wx 
package, which have been assigned some specific integers.
The following code:

print wx.ID_ABOUT, wx.ID_EXIT

placed in an appropriate place in a wxPython program, produces 
this result:

5014 5006

So wx.ID_ABOUT and wx.ID_EDIT are different by about 4,900. :)


> When would you use
> wx.ID_ABOUT or wx.ID_EXIT?  

I think the underlying operating system applies some default
actions to widgets with those id's, so if you want those default actions 
to apply, you would use those id's.  

For instance, on a Mac, an 
item with the id wx.ID_ABOUT is placed in a specific location in 
a menu under the default menu bar item "Python".  So for instance,
if I create a menu item called "Cool Files" with the id wx.ID_ABOUT, 
and I add it in a menu under a menu bar item named "My Stuff", 
"Cool Files" will be redirected to the menu under "Python", and 
it won't appear in the menu under "My Stuff".  I can set the text 
of an item with the wx.ID_ABOUT id, but not its location.

As another example, on a Mac, when I try using the id wx.ID_EXIT, 
like this:

class MyFrame(wx.Frame):
    def __init__(self):
        wx.Frame.__init__(self, None)
        
        mbar = wx.MenuBar()
        menu = wx.Menu()
        menu.Append(wx.ID_EXIT, "Exit...")
        mbar.Append(menu, "Test") 
       
        self.SetMenuBar(mbar)

it doesn't work at all: no menu item with the name "Exit..." appears 
anywhere.  Apparently, a Mac won't let me you use that id.  Strangely 
enough, if I use -1 for the id instead, which means I let wxPython 
choose the id for me, the menu item appears in the location I specify, 
but if I set the text to exactly "Exit", then "Exit" is automatically 
changed to "Quit".  Therefore, a Mac won't allow me to use the id 
wx_ID_EXIT nor the name "Exit" for my menu items.  

> 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?

"If you pass a specific number[as the id], it is your responsibility to 
make sure that you do not duplicate ID numbers within a frame or 
reuse one of the predefined constants."  ("wxPython in Action", p.42)

Therefore, if you are going to specify your own id's, you should use 
a wxPython program to print out wx.ID_LOWEST and wx.ID_HIGHEST 
and not use id's in that range.  I get 4999 and 5999 as the values for 
those variables.  You can also use:

wx.Register(anInt) 

to make sure your chosen id is not reproduced by calls to wx.NewId(), 
which apparently also is called when you specify the id as -1 or wx.ID_ANY.

>Is the event "number space" considered to be global?

I'm not sure what you mean by that, but I think the answer is yes.  
wxPython in Action(p.42) says that id's must be unique within a frame, 
but the authors recommend you use unique id numbers throughout 
your whole application to keep from confusing yourself when writing 
event handlers.

> 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 handler to call?

One use case: Bind() is defined like this,

Bind(event, handler, source=None, id=-1, id2=-1)

The "id" parameter allows you to specify the source by id rather 
than specifying a name (the name being a reference to a widget).  
If you don't have a reference to the widget, you can specify the 
id instead:

---
import wx

class MyPanel(wx.Panel):
    def __init__(self, parent):
        wx.Panel.__init__(self, parent)
        button = wx.Button(self, 100, "Click me")

class MyFrame(wx.Frame):
    def __init__(self):
        wx.Frame.__init__(self, None)
        panel = MyPanel(self)
        self.Bind(wx.EVT_BUTTON, self.someFunc, id=100) 

    def someFunc(self, event):
        print "hello"

app = wx.PySimpleApp()
frame = MyFrame()
frame.Show()
app.MainLoop()
----

I doubt too many people would consider that good programming 
practice though.  You're essentially using a global variable to store 
objects, and then your class is reaching out from its black box to 
pull in those global values.  If something or someone changes 
those global variables, your program will most likely crash.  
Furthermore, with only a slight alteration to the code, you don't 
have to rely on a global variable:

..
*self*.button = wx.Button(self, 100, "Click me")
...
...
self.Bind(wx.EVT_BUTTON, self.someFunc, *panel.button*)
...

As I see it, a better use case for id's is using the Bind() method's 
"id" and "id2" parameters together.  When used together, they 
specify a range of widget id's that the event handler should 
apply to. That could save you from having to type, say, 10 Bind() 
statements to apply one event handler to 10 different widgets.

I'm new to wxPython so I don't know if specifying id's is done 
much in practice.  So, it would be helpful if some experienced 
people posted the circumstances under which they specify their own 
id's in a program.

> I've whined about this before, but the idea of using global ID
> numbers to hook things together really grates on my
> sensibilities.  It's painful to look at nice Python code where
> people pull a bunch of arbitrary integer values out of a hat in
> order to tell object A to call a method in object B when
> someting happens. You'd think the underlying library was
> written in Fortran IV instead of a purportedly object-oriented
> language like C++.
> 

As I understand things, it's worse than that.  In Widows, the 
underlying operating system is written in C. C++ uses a collection 
of classes to wrap the underlying C code to give you an object 
oriented interface to the operating system, and then Python wraps 
the C++ code.  

> Yes, I realize there are efforts to hide wxWidget's low-level
> ugliness from Python programmers.  And yes, I realize it gives
> you the capabilities to do neat and powerful things that I've
> never needed to do and never will. I don't know what percentage
> of developers need those capabilities -- I just wish the rest
> of us didn't have to suffer because of it.

lol.  Doing Windows GUI programming directly with the C api is 
pretty difficult. Using C++ classes that wrap the C code makes 
things easier but it is still difficult--even with a good IDE--and 
it presents its own mysteries.  Compared to those options, 
specifying -1 for an id when using wxPython is a breeze.






More information about the wxpython-users mailing list