Catching wx events

Cruelemort ian.inglis at gmail.com
Thu Jan 18 11:58:39 EST 2007


Chris Mellon wrote:

> On 18 Jan 2007 06:12:17 -0800, Cruelemort <ian.inglis at gmail.com> wrote:
> > Hello all,
> >
> > I am new to this group (and new to Python) and was hoping someone would
> > be able to help me with something, it is not so much a problem it is
> > more of a general interest query about something i have a solution too
> > but am not sure it is the correct one.
> >
> > I have a class that contains a string ID and a name, and a list
> > containing a few objects of this type, i need to loop through this list
> > and create a button for each object (with the name as the label) i have
> > done this with the following code -
> >
> >                 for chan in self._channellist:
> >                         channelbutton = wx.Button(self, id=-1,
> > label=chan.getName())
> >
> > channelbutton.Bind(wx.EVT_BUTTON,self._channelChanged)
> >
> > My question is this - in the _channelChanged method, how do i know
> > which button has been pressed when i enter the channel changed method,
> > and so how do i retrieve the appropriate object depending on which
> > button has been pressed?
> >
> > I have potentially solved this problem using the UserData property in a
> > sizer, i have added all the buttons to a sizer for display purposes and
> > so SizerItem objects have been created, i can then set the original
> > object to the UserData object by putting the following line of code in
> > the loop
> >
> >                         sizeritem =
> > self.topsizer.Add(channelbutton,0,wx.ALIGN_RIGHT, userData=chan)
> >
> > This way i can retrieve the item in the _channelChanged method with the
> > following -
> >
> >         def _channelChanged(self, event):
> >                 eventobj = event.GetEventObject()
> >                 chan = self.topsizer.GetItem(eventobj).GetUserData()
> >
> >
> > This works fine but by looking at the API it would appear the UserData
> > property is not really designed for this use ("userData - Allows an
> > extra object to be attached to the sizer item, for use in derived
> > classes when sizing information is more complex than the proportion and
> > flag will allow for").
> >
> > Another option would be to derive my own Button class and include the
> > object in there.
> >
> > Any advice on the best way to solve this problem would be appreciated.
> >
>
> Exactly how I would do it depends on the rest of the application. I
> would probably derive my own button - never be afraid to subclass.
>
> You could also generate the buttons IDs up front, and maintain a
> mapping between the IDs and the channels, like so:
>
> self.mapper = {}
> for channel in self.channels:
>     id = wx.NewId()
>     self.mapper[id] = channel
>     channelbutton = wx.Button(self, id=id, label=channel.getName())
>
>
> def channelChanged(self, event):
>     channel = self.mapper[event.Id]
>
>
> You could also use closures (lambdas or via a factory function) to
> bind the channel at the time you create the button:
>
> for channel in self.channels:
>     channelbutton = wx.Button(self, label=channel.getName())
>     self.Bind(wx.EVT_BUTTON, lambda event:
> self.channelChanged(channel), source=channelbutton)
>
> def channelChanged(self, channel):
>     print "Channel changed to ", channel.getName()

Two good ideas, i used the mapping system, works and seems like a
slightly more elegant way of doing things.

Many thanks!

Ian




More information about the Python-list mailing list