By using this site, you agree to our updated Privacy Policy and our Terms of Use. Manage your Cookies Settings.
443,965 Members | 1,962 Online
Bytes IT Community
+ Ask a Question
Need help? Post your question and get tips & solutions from a community of 443,965 IT Pros & Developers. It's quick & easy.

Don't understand wxPython ids

P: n/a
I've decided to learn wxPython, and I'm afraid I just don't
grok the whole "id" thing where you have to pull unique
integers out of your, er, the air and then use those to refer
to objects:

From whe wxPython wiki examples:

self.button =wxButton(self, 10, "Save", wxPoint(200, 325))
EVT_BUTTON(self, 10, self.OnClick)

Does the 10 have any function other than as a handle that
allows you to refer to self.button in the EVT* call?

You're supposed to just make up unique id numbers for objects
when a) they've already got unique id numbers [at least the id
builtin thinks so] and b) they've got names that make things
even more readable?

This feels very assmebly-level. No, it's even worse than
assembly language, since even assembly language has labels and
symbols.

Why not this:

self.button =wxButton(self, 10, "Save", wxPoint(200, 325))
EVT_BUTTON(self, self.button, self.OnClick)

Or better yet this:

self.button =wxButton(self, 10, "Save", wxPoint(200, 325), action=self.OnClick)

This last way seems pretty intuitive...

Can somebody clue me in on the advantages of the
progrmmer-generated integer id numbers for objects?

--
Grant Edwards grante Yow! Now KEN and BARBIE
at are PERMANENTLY ADDICTED to
visi.com MIND-ALTERING DRUGS...
Jul 18 '05 #1
Share this Question
Share on Google+
19 Replies


P: n/a
Grant Edwards wrote:
I've decided to learn wxPython, and I'm afraid I just don't
grok the whole "id" thing where you have to pull unique
integers out of your, er, the air and then use those to refer
to objects:

From whe wxPython wiki examples:

self.button =wxButton(self, 10, "Save", wxPoint(200, 325))
EVT_BUTTON(self, 10, self.OnClick)

Does the 10 have any function other than as a handle that
allows you to refer to self.button in the EVT* call?
AFAIK, yes. But then again, I don't know much. Note that you can use -1
as the id and the button will create it's own unique id for you. Then
all you have to do is call button.GetId() whenever you need it.
You're supposed to just make up unique id numbers for objects
when a) they've already got unique id numbers [at least the id
builtin thinks so] and b) they've got names that make things
even more readable?

This feels very assmebly-level. No, it's even worse than
assembly language, since even assembly language has labels and
symbols.

Why not this:

self.button =wxButton(self, 10, "Save", wxPoint(200, 325))
EVT_BUTTON(self, self.button, self.OnClick)

Or better yet this:

self.button =wxButton(self, 10, "Save", wxPoint(200, 325), action=self.OnClick)

This last way seems pretty intuitive...

Can somebody clue me in on the advantages of the
progrmmer-generated integer id numbers for objects?


In the new wxPython (2.5.1.5) there's an easier way to bind events
without using ids at all using widget.Bind, like this:

import wx

class MyFrame(wx.Frame):
def __init__(self, *args, **kwargs):
wx.Frame.__init__(self, *args, **kwargs)

self.button = wx.Button(self, -1, "What's my id?")
self.button.Bind(wx.EVT_BUTTON, self.OnButtonPress)

def OnButtonPress(self, event):
self.button.SetLabel("My id is: %d" % self.button.GetId())
app = wx.App()
frame = MyFrame(None, -1, "Events and ids")
frame.Show(True)
app.MainLoop()

I can only think of one reasn why they chose to use ids in the first
place. Assigning many objects the same id allows you to use one EVT_*
call for those objects. But is that really a useful feature? Who knows?

greg
Jul 18 '05 #2

P: n/a
In article <BO******************@newsread1.news.pas.earthlink .net>, Greg Krohn wrote:
AFAIK, yes. But then again, I don't know much. Note that you can use -1
as the id and the button will create it's own unique id for you. Then
all you have to do is call button.GetId() whenever you need it.
Ya know, now that you mention it, I think I actually new that
once a couple years back.
Can somebody clue me in on the advantages of the
progrmmer-generated integer id numbers for objects?


In the new wxPython (2.5.1.5) there's an easier way to bind events
without using ids at all using widget.Bind, like this:

import wx

class MyFrame(wx.Frame):
def __init__(self, *args, **kwargs):
wx.Frame.__init__(self, *args, **kwargs)

self.button = wx.Button(self, -1, "What's my id?")
self.button.Bind(wx.EVT_BUTTON, self.OnButtonPress)


That's definitely getting closer to what I would expect in
something designed in the last 15-20 years, though passing the
binding as a parameter to wx.Button() sure seems like the
obvious solution for 90% of the cases I run into. Perhaps I'm
too used to Tk.
I can only think of one reasn why they chose to use ids in the first
place. Assigning many objects the same id allows you to use one EVT_*
call for those objects. But is that really a useful feature? Who knows?


That's about the only thing I could think of. The few
situations where I'd have wanted to do someting like that I'd
gladly put a for-loop iterating over a list of objects in
exchange for being able to use single-line of code the other
90% of the time.

--
Grant Edwards grante Yow! I'm young... I'm
at HEALTHY... I can HIKE
visi.com THRU CAPT GROGAN'S LUMBAR
REGIONS!
Jul 18 '05 #3

P: n/a
I can only think of one reasn why they chose to use ids in the first
place. Assigning many objects the same id allows you to use one EVT_*
call for those objects. But is that really a useful feature? Who knows?

That's about the only thing I could think of. The few
situations where I'd have wanted to do someting like that I'd
gladly put a for-loop iterating over a list of objects in
exchange for being able to use single-line of code the other
90% of the time.


Right, there a couple of special cases to think of when designing event
bindings for a gui toolkit. One is where you want multiple controls to
share the same event handler (like a button and a menu item that do the
same thing). Another case is allowing people to change event bindings
"on the fly", after a window constructor has already been called and the
window set up.

I proposed some changes similar to you, see this thread:
http://lists.wxwidgets.org/cgi-bin/e...kojpgmpdpmio#b
but nothing came out of it. I did code up an implementation for Wax
(http://wiki.wxpython.org/index.cgi/Wax ), but I don't know if it was
included.
Jul 18 '05 #4

P: n/a
Greg Krohn wrote:
I can only think of one reasn why they chose to use ids in the first
place.
Don't forget how old wxWidgets is, and that it has to interoperate
with the underlying toolkits.
Assigning many objects the same id allows you to use one EVT_*
call for those objects. But is that really a useful feature? Who knows?


Here is how I use the same id in multiple locations. I can have a
menu entry, a toolbar button, and a button inside some HTML all
invoke the same function. The only coupling between them is
the id number.

You can also use id ranges in wxPython 2.5 which makes it easy to
send a whole bunch of different items to the same handler.

class FooFrame(wx.Frame):
ID_FILE_DELETE=wx.NewId()

def _init_(...):
...
menu.Append(self.ID_FILE_DELETE, "&Delete", "Delete the file")
....
toolbar.AddLabelTool(self.ID_FILE_DELETE, "Delete", ....)
....
wx.EVT_MENU(self, self.ID_FILE_DELETE, self.OnFileDelete)
....
wx.EVT_BUTTON(self, self.ID_FILE_DELETE, self.OnFileDelete)
....

def OnStateChange(...):
....
self.GetToolBar().EnableTool(self.ID_FILE_DELETE, True)
....

In my HTML:

<wxp class="Button" module="wx">
<param name="label" value="Delete ..."/>
<param name="id" value="gui.FooFrame.ID_FILE_DELETE"/>
</wxp>

Roger
Jul 18 '05 #5

P: n/a
Grant Edwards wrote:
That's definitely getting closer to what I would expect in
something designed in the last 15-20 years, though passing the
binding as a parameter to wx.Button() sure seems like the
obvious solution for 90% of the cases I run into. Perhaps I'm
too used to Tk.


I totally agree with you. The Tk way seems much more natural.
I can only think of one reasn why they chose to use ids in the first
place. Assigning many objects the same id allows you to use one EVT_*
call for those objects. But is that really a useful feature? Who knows?

That's about the only thing I could think of. The few
situations where I'd have wanted to do someting like that I'd
gladly put a for-loop iterating over a list of objects in
exchange for being able to use single-line of code the other
90% of the time.


Ditto. You'd think it wouldn't be so hard to add a kwarg for it. At
least if it's something you can add on the Python side. Hmmm.
greg
Jul 18 '05 #6

P: n/a
On 2004-04-28, Doug Holton <in****@spam.here> wrote:
I can only think of one reasn why they chose to use ids in the
first place. Assigning many objects the same id allows you to
use one EVT_* call for those objects. But is that really a
useful feature? Who knows?
That's about the only thing I could think of. The few
situations where I'd have wanted to do someting like that I'd
gladly put a for-loop iterating over a list of objects in
exchange for being able to use single-line of code the other
90% of the time.


Right, there a couple of special cases to think of when
designing event bindings for a gui toolkit. One is where you
want multiple controls to share the same event handler (like a
button and a menu item that do the same thing).


Just pass the same function to both of them when you create
them?
Another case is allowing people to change event bindings "on
the fly", after a window constructor has already been called
and the window set up.
Provide a method to set the action for an object instance after
it's been created.

Both of these have been SOP in other GUI toolkits for a dog's
age, and I can't figure out any benefit to the ID scheme.
Using an outside function to reach in and torque on the
object's internals seems so un-Pythonesque. But, all sorts of
smart people rave about wxPython, so I thought there must be
some benefit to the ID scheme that I'm missing.
I proposed some changes similar to you, see this thread:
http://lists.wxwidgets.org/cgi-bin/e...kojpgmpdpmio#b
but nothing came out of it. I did code up an implementation
for Wax (http://wiki.wxpython.org/index.cgi/Wax ), but I don't
know if it was included.

--
Grant Edwards grante Yow! Nice decor!
at
visi.com
Jul 18 '05 #7

P: n/a
On 2004-04-28, Roger Binns <ro****@rogerbinns.com> wrote:
Here is how I use the same id in multiple locations. I can have a
menu entry, a toolbar button, and a button inside some HTML all
invoke the same function. The only coupling between them is
the id number.

ID_FILE_DELETE=wx.NewId()
...
menu.Append(self.ID_FILE_DELETE, "&Delete", "Delete the file")
....
toolbar.AddLabelTool(self.ID_FILE_DELETE, "Delete", ....)
....
wx.EVT_MENU(self, self.ID_FILE_DELETE, self.OnFileDelete)
....
wx.EVT_BUTTON(self, self.ID_FILE_DELETE, self.OnFileDelete)
I understand, but compare the above code with this:
menu.Append("&Delete", "Delete the file", action=self.OnFileDelete)
....
toolbar.AddLabelTool("Delete", action=self.OnFileDelete)
Which is easier to understand at a glance?
[pardon the re-arrangement]
You can also use id ranges in wxPython 2.5 which makes it easy to
send a whole bunch of different items to the same handler.


Now _that's_ something you can actually point to as a "feature"
of the ID scheme.

--
Grant Edwards grante Yow! .. I want FORTY-TWO
at TRYNEL FLOATATION SYSTEMS
visi.com installed within SIX AND A
HALF HOURS!!!
Jul 18 '05 #8

P: n/a
On 2004-04-28, Greg Krohn <gr**@invalid.invalid> wrote:
The few situations where I'd have wanted to do someting like
that I'd gladly put a for-loop iterating over a list of
objects in exchange for being able to use single-line of code
the other 90% of the time.


Ditto. You'd think it wouldn't be so hard to add a kwarg for it. At
least if it's something you can add on the Python side. Hmmm.


I guess it's simple enough to subclass the widgets I use and
add one, but it feels like going to buy a new car and having to
bring your own steering wheel.

--
Grant Edwards grante Yow! Wow! Look!! A stray
at meatball!! Let's interview
visi.com it!
Jul 18 '05 #9

P: n/a
Grant Edwards wrote:
I guess it's simple enough to subclass the widgets I use and
add one, but it feels like going to buy a new car and having to
bring your own steering wheel.


Well, no I meant importing something like this each time (it doesn't
actually work, BTW):
import wx

#Subclass wx.PyEventBinder to catch all EVT_* args
class MyPyEventBinder(wx.PyEventBinder):
def __init__(self, *args, **kwargs):
# Look for EVT_* args, bind them and del them
for kw in kwargs:
if kw.startswith('EVT_'):
self.Bind(getattr(wx, kw), kwargs[kw])
del kwargs[kw]
wx.PyEventBinder.__init__(self, *args, **kwargs)

#A little behind-the-scenes switcheroo
wx.PyEventBinder = MyPyEventBinder

if __name__ == '__main__':

class MyFrame(wx.Frame):
def __init__(self, *args, **kwargs):
wx.Frame.__init__(self, *args, **kwargs)
self.button = wx.Button(self, -1, "What's my id?",
EVT_BUTTON=self.OnButtonPress)

def OnButtonPress(self, event):
self.button.SetLabel("My id is: %d" % self.button.GetId())

app = wx.App()
frame = MyFrame(None, -1, "Events and ids")
frame.Show(True)
app.MainLoop()

If I can't figure this out, I'll try subclassing individule widgets and
throwing it in a module.

greg
Jul 18 '05 #10

P: n/a
Grant Edwards wrote:
I understand, but compare the above code with this:
menu.Append("&Delete", "Delete the file", action=self.OnFileDelete)
....
toolbar.AddLabelTool("Delete", action=self.OnFileDelete)


Which is easier to understand at a glance?


If it is all in one place in one function then it is no big deal.
In reality if you have editable toolbars, menus loaded from definitions
elsewhere and stuff scattered across several modules then using
ids makes that easier.

Roger

Jul 18 '05 #11

P: n/a
Greg Krohn wrote:
If I can't figure this out, I'll try subclassing individule widgets and
throwing it in a module.

greg


Here we go. Use the attached module like this:

#yourmodule.py
import wx
from event_kwargs import *

.... your code ...

self.ok_button = wx.Button(self, -1, "Ok", EVT_BUTTON=self.OnOk)

....more code...
The only testing I've done is in the "if __name__ == '__main__'" part of
the module. I *haven't* tested all the widgets and events, but they
should theoretically work.

greg

#event_kwargs.py
#version: 0.0.1
#author: Greg Krohn

import wx

def _event_wrap(klass):
# Backup the original __init__
klass.__classic_init__ = klass.__init__

# The new __init__ that will deal with EVT_* kwargs
def new__init__(self, *args, **kwargs):
binds = {} # The EVT_* kwargs
new_kwargs = {} # The kwargs minus EVT_* kwargs (to pass to the orig __init__)

# Sort the kwargs into binds or new_kwargs
for kw in kwargs:
if kw.startswith('EVT_'):
binds[kw] = kwargs[kw]
else:
new_kwargs[kw] = kwargs[kw]

# Call the orig, __init__ with the cleaned-up kwargs
kwargs = new_kwargs
self.__classic_init__(*args, **kwargs)

# bind the EVT_* kwargs
for evt in binds:
self.Bind(getattr(wx, evt), binds[evt])

klass.__init__ = new__init__
return klass

#wrap the controls
for obj in dir(wx):
if hasattr(getattr(wx, obj), '__bases__'):
if wx.core.Control in getattr(wx, obj).__bases__:
exec "wx.%s = _event_wrap(wx.%s)" % (obj, obj)

if __name__ == '__main__':

class MyFrame(wx.Frame):
def __init__(self, *args, **kwargs):
wx.Frame.__init__(self, *args, **kwargs)
self.sizer = wx.BoxSizer(wx.VERTICAL)
self.SetSizer(self.sizer)

self.button = wx.Button(self, -1, "What's my id?", EVT_BUTTON=self.OnButtonPress)
self.sizer.Add(self.button, 0, flag=wx.EXPAND)
self.text = wx.TextCtrl(self, -1, style=wx.TE_PROCESS_ENTER , EVT_TEXT_ENTER=self.OnTextEnter)
self.sizer.Add(self.text, 1, flag=wx.EXPAND)
def OnButtonPress(self, event):
self.button.SetLabel("My id is: %d" % self.button.GetId())

def OnTextEnter(self, event):
self.text.SetValue(self.text.GetValue() + '<ENTER>')
self.text.SetInsertionPointEnd()

app = wx.App()
frame = MyFrame(None, -1, "event_kwargs.py")
frame.Show(True)
app.MainLoop()
Jul 18 '05 #12

P: n/a
On 2004-04-28, Greg Krohn <gr**@invalid.invalid> wrote:
Here we go. Use the attached module like this:

#yourmodule.py
import wx
from event_kwargs import *

... your code ...

self.ok_button = wx.Button(self, -1, "Ok", EVT_BUTTON=self.OnOk)

...more code...
I _like_ it. Very clever!
The only testing I've done is in the "if __name__ == '__main__'" part of
the module. I *haven't* tested all the widgets and events, but they
should theoretically work.


I'll certainly give it a try. Thanks!

--
Grant Edwards grante Yow! I'm in LOVE with
at DON KNOTTS!!
visi.com
Jul 18 '05 #13

P: n/a
Roger Binns wrote:
Here is how I use the same id in multiple locations. I can have a
menu entry, a toolbar button, and a button inside some HTML all
invoke the same function. The only coupling between them is
the id number.


Giving an identifier to a command so that it can be
invoked in multiple ways is a good idea, but it would
be much more Pythonic if a *name* could be used as the
identifier rather than a number.

Use of a number here seems to be entirely the result
of blindly carrying over a feature of the C++-oriented
API into Python.

--
Greg Ewing, Computer Science Dept,
University of Canterbury,
Christchurch, New Zealand
http://www.cosc.canterbury.ac.nz/~greg

Jul 18 '05 #14

P: n/a
On 2004-04-28, Greg Krohn <gr**@invalid.invalid> wrote:
Here we go. Use the attached module like this:

#yourmodule.py
import wx
from event_kwargs import *


Hmm. I guess it's time to upgrade to 2.5.

--
Grant Edwards grante Yow! I'm in a twist
at contest!! I'm in a
visi.com bathtub! It's on Mars!! I'm
in tip-top condition!
Jul 18 '05 #15

P: n/a
On 2004-04-29, Grant Edwards <gr****@visi.com> wrote:
#yourmodule.py
import wx
from event_kwargs import *


Hmm. I guess it's time to upgrade to 2.5.


I guess not. It appears it would require upgrading so many
other things it would probably take at least a week or two. :(

--
Grant Edwards grante Yow! I just heard the
at SEVENTIES were over!! And
visi.com I was just getting in touch
with my LEISURE SUIT!!
Jul 18 '05 #16

P: n/a
Grant Edwards <gr****@visi.com> wrote in message news:<40***********************@newsreader.visi.co m>...
You're supposed to just make up unique id numbers for objects
when a) they've already got unique id numbers [at least the id
builtin thinks so] and b) they've got names that make things
even more readable?


"Wax" is a wxPython wrapper under development at:

http://zephyrfalcon.org/labs/
http://zephyrfalcon.org/weblog/arch_Wax.html

Wax has a much more Pythonic API than wxPython, and gets rid of the
numeric IDs completely. For example:

b = Button(parent, "Save", onsave)

Alternately:

b = Button(parent, "Save")

# ...

b.OnClick = onsave

Here's a longer snippet from the Wax primer:

def CreateMenu(self):
menubar = MenuBar()

menu1 = Menu(self)
menu1.Append("&New", self.New, "Create a new file")
menu1.Append("&Open", self.Open, "Open a file")
menu1.Append("&Save", self.Save, "Save a file")

menubar.Append(menu1, "&File")

self.SetMenuBar(menubar)
Jul 18 '05 #17

P: n/a
On 2004-04-29, Matt Brubeck <mb******@cs.hmc.edu> wrote:
"Wax" is a wxPython wrapper under development at:

http://zephyrfalcon.org/labs/
http://zephyrfalcon.org/weblog/arch_Wax.html

Wax has a much more Pythonic API than wxPython, and gets rid of the
numeric IDs completely.


I like it! I'm currently downloading a set of Mandrake 10 CDs
so I can run wxPython 2.5. Hopefully the upgrade won't kill
more than a few days. Once the system upgrade is done, I'll
give Wax a try.

--
Grant Edwards grante Yow! ... I want FORTY-TWO
at TRYNEL FLOATATION SYSTEMS
visi.com installed withinSIX AND A
HALF HOURS!!!
Jul 18 '05 #18

P: n/a
Greg Ewing wrote:
Use of a number here seems to be entirely the result
of blindly carrying over a feature of the C++-oriented
API into Python.


Honestly, that's exactly what it is. wxPython is a wrapper around a VERY
large C++ toolkit. It uses SWIG to create wrappers that pretty much
match the C++ API. This has had two big advantages:

1) Robin Dunn could actually get it working in a relatively short period
of time

2) the docs match as well, so We had a pretty complete (if confusing)
set of docs from the beginning

Note that neither of these has anything to do with what a good Python
API is, but I don't think we'd have wxPython at all if Robin had set out
to make the best API he could.

FWIW, wxPython is slowly growing more "pythonic" wrappers. There are
also a couple of efforts to make another layer between wxPython and the
user:

PythonCard
Wax
MindWrapper

Of these, PythonCard is probably the farthest along.

-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

Ch**********@noaa.gov
Jul 18 '05 #19

P: n/a
Greg Ewing wrote:
Giving an identifier to a command so that it can be
invoked in multiple ways is a good idea, but it would
be much more Pythonic if a *name* could be used as the
identifier rather than a number.
That is kinda what my code is doing :-) The name just
happens to be a static class member mapped to an integer.
Use of a number here seems to be entirely the result
of blindly carrying over a feature of the C++-oriented
API into Python.


There has been much debate about this on the wxPython lists.
One school of thought is to make wxPython as "Pythonic" as
possible, with its own set of documentation and own
community. The fact that there is a C++ library underneath
would be a minor implementation detail.

A second school of thought (to which I belong) is that wxPython
should stick to the C++ API closely unless changes significantly
improve developer productivity. The means that wxPython
remains a member of the wxWidgets community, the standard
wxWidgets documentation remains the same and appropriate,
and it is easy to translate C++/Perl/other language wxWidgets
programs into wxPython and vice versa even for the people
who do not know the languages.

Of course there is no "right answer" as to what is best,
and ultimately it is up to Robin and his good taste. At
the moment wxPython is largely in the second camp, with
some amount of the former present. Some people have
implemented stuff in the former camp on top of wxPython
(eg wax).

People are of course welcome to criticise wxWidgets, but
as someone who as actually done programs on multiple
different platforms and GUI toolkits, I am very impressed.
I'll listen to people who have actually written something
that runs on several platforms and operating systems first.

Roger
Jul 18 '05 #20

This discussion thread is closed

Replies have been disabled for this discussion.