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