views:

117

answers:

3

I'm doing a little wxPython work today and I've got this piece of code (I've stripped out the irrelevant parts):

        def CreateRowOne(self, pan):
            hbox1 = wx.BoxSizer(wx.HORIZONTAL)
            hbox1.Add(wx.Button(pan, -1, "250 Words"), 1, wx.EXPAND | wx.ALL)
            hbox1.Add(wx.Button(pan, -1, "500 Words"), 1, wx.EXPAND | wx.ALL)
            hbox1.Add(wx.Button(pan, -1, "750 Words"), 1, wx.EXPAND | wx.ALL)
            return hbox1

How do you get the ID of the buttons that were created, so I can bind them to a handler? Normally, I'd do this:

            button1 = wx.Button(...)
            button2 = wx.Button(...)

            ...

            self.Bind(wx.EVT_BUTTON, self.Blah, button1.GetID())
            self.Bind(wx.EVT_BUTTON, self.Blah2, button2.GetID())

but I didn't give an identifier to any of the buttons. Am I going to have to manually assign the ID numbers?

+2  A: 

Am I going to have to manually assign the ID numbers?

No, putting -1 or using wx.NewId() will give you autogenerated ID.

and You can always get id with button1.GetID() or button1.Id back anytime.

--

UPDATE:

ID_BUTTON1 = wx.NewId()

hbox1.Add(wx.Button(pan, ID_BUTTON1, "250 Words"), 1, wx.EXPAND | wx.ALL)

self.Bind(wx.EVT_BUTTON, self.Blah, ID_BUTTON1)
S.Mark
But I didn't create a button1 or a button2, I did this:"hbox1.Add(wx.Button(pan, -1), 1, wx.EXPAND | wx.ALL)"
cornjuliox
Ok, Updated, You can do like that too.
S.Mark
So basically for every widget I need to have a reference to an ID number somewhere, whether I've assigned it manually or not?
cornjuliox
you do not need ID to bind, see my answer
Anurag Uniyal
A: 

I recommend not doing "sizer.Add(wx.Button(...))". It's better to separate widget creation and layout. Is there a compelling reason to write your code the way you have? Why not write it like this:

button1=wx.Button(pan, wx.ID_ANY, ...)
button2=wx.Button(pan, wx.ID_ANY, ...)
...
hbox1.Add(button1)
hbox1.Add(button2)
...
self.Bind(wx.EVT_BUTTON, self.Blah, button1.GetID())
self.Bind(wx.EVT_BUTTON, self.Blah2, button2.GetID())

There's simply no gain in combining button creation and adding it to a sizer in one line.

Personally I see even greater value in assigning IDs, but that can be onerous for a large number of widgets. I generally only do that for "significant" widgets -- widgets I refer to in other parts of the code. My code typically looks like:

ID_BUTTON1 = wx.NewID()
IO_BUTTON2 = wx.NewID()

class ...:
   ...
   button1 = wx.Button(self, ID_BUTTON1, ...)
   ...
   self.Bind(wx.EVT_BUTTON, ID_BUTTON1, ...)
   ...

I think this makes the code easier to understand and easier to maintain over time.

Bryan Oakley
The tutorials I followed when I first started learning wxPython looked that way, they combined widget creation and layout in one line. I always assumed that wxPython had some way of retrieving IDs in the absence of an identifier or manually defined ID, plus, doing it the "longer" way just seemed to go against what I learned - that is, to get more done with less code.
cornjuliox
Don't let the desire to create less code cause you to write an incorrect amount of code. While we should all strive to write less code, we should write as few lines of code as necessary but no fewer. Remember, your ultimate goal is to write code that a) works, and b) is maintainable. Cramming code into fewer lines doesn't work toward either of those goals IMO.
Bryan Oakley
A: 

You can get id by control.GetID() but you do not need to get ID to bind, you can just do this

self.btn.Bind(wx.EVT_BUTTON, self._onBtnClick)

It is preferable(id should be implementation detail) and short e.g. in this sample

import wx

app = wx.PySimpleApp()
frame = wx.Frame(None)
btn = wx.Button(frame, -1, "anurag")
btn.Bind(wx.EVT_BUTTON, lambda e:wx.MessageBox("Wow it works"))
frame.Show()
app.SetTopWindow(frame)
app.MainLoop()
Anurag Uniyal