Buttons and Events - Trying the Obstacle Course

'''

Sorry for posting much code. this is my Wiki Obstacle Course
Fun With Sizers
program, cut down to the minimum to illustrate my questions/problems.

I want to bind my buttons to a common OnClick handler. The handler
should report the button size in a popup dialog.

Sounds simple but I do not see how to do it. I see varying code styles
but I do not get the nuances.

creating buttons: <<<<<<<<<<<<<<<<<<<<<<<<<<

self.r1b1 = wx.Button(self, ID_R1B1, 'Top', wx.Point(-1,-1), wx.Size(-1,-1))
r1b2 = wx.Button(self, ID_R1B2, 'Center', wx.Point(-1,-1), wx.Size(-1,-1))

The 'self' style is the only way I can get access to the button from within the event handler.

What is the difference between the two styles? (I realize that is a python objects question rather than a wxpython question.)

size and position with Sizers: <<<<<<<<<<<<<<<<<<<<<<<<<<

r1b2 = wx.Button(self, ID_R1B2, 'Center', wx.Point(-1,-1), wx.Size(-1,-1))
r1b2 = wx.Button(self, ID_R1B2, 'Center', (-1,-1), (-1,-1))
r1b2 = wx.Button(self, ID_R1B2, 'Center', 'pos(-1,-1)', wx.Size(-1,-1))

I am using the first style because that matches my reading of the method
signatures in the wxWindows doc. But elsewhere I see stuff that looks like the second or third approach.

Which is preferred? Which is correct? How can a vanilla tuple like (-1,-1)
stand in for a wx.Point or wx.Size? (Python is dynamically but strongly
typed).

Either way, it seems like an awful lot of typing just to say
'i am not specifying any values here'.

binding events: <<<<<<<<<<<<<<<<<<<<<<<<<<

self.Bind(wx.EVT_BUTTON, self.OnClick, id = ID_R1B3)
self.Bind(wx.EVT_BUTTON, self.OnBob, r1b4)

Again, I see both approaches in the demo or elsewhere. Which is preferred? Which is correct? What are the implications?

Neither approach seems to give the event handler access to the button though.

event handlers: <<<<<<<<<<<<<<<<<<<<<<<<<<

Generally, within a handler, the event argument seems to be a reference to the control that experienced the event. Certain functions that seem to attributes of controls rather than a wx.Event seem to be available.

I guess. But I cannot get wx.Button functions thru the event.

If I created the button as "self.mybutt=wx.Button(...)" I can reference
self.mybutt in the handler. But I am not able to access the control in any generic or unnamed way.

Thanks for any thoughts. Reading the wxWindows doc on event handling is not quite getting me there.

'''

···

#
# jim.py
#

import os
import sys
sys.path.append('\Python23\Lib\site-packages\wx')

import wx

ID_R1B1 = 121
ID_R1B2 = 122
ID_R1B3 = 123
ID_R1B4 = 124

class MainWindow(wx.Frame):
     """ We simply derive a new class of Frame. """
     def __init__(self,parent,id,title):
         # Frame(parent, id, title, wx.Size(w,h), stylebits)
         wx.Frame.__init__(self,parent,-4, title, size = ( -1,-1),
                 style=wx.DEFAULT_FRAME_STYLE|wx.NO_FULL_REPAINT_ON_RESIZE)
#
# end class MainWindow
#

class Form1(wx.Panel):
     ''' Box Sizer Obstacle Course '''
     def __init__(self, parent, id):
         wx.Panel.__init__(self, parent, id)

         bs = wx.BoxSizer(wx.VERTICAL)

         # rowsizer1, contains 4 buttons
         rs1 = wx.BoxSizer(wx.HORIZONTAL)
         # Sizer.Add(control, proportion=0, stylebits=0, borderbits=0)
         bs.Add(rs1, 2, wx.EXPAND)

         # Button(parent, id, label, wx.Point(x,y)
         # , wx.Size(w,h)=defaultsize, stylebits=0, validator
         # , name = 'button'
         self.r1b1 = wx.Button(self, ID_R1B1, 'Top', wx.Point(-1,-1), wx.Size(-1,-1))
         r1b2 = wx.Button(self, ID_R1B2, 'Center', wx.Point(-1,-1), wx.Size(-1,-1))
         r1b3 = wx.Button(self, ID_R1B3, 'Bottom', wx.Point(-1,-1), wx.Size(-1,-1))
         r1b4 = wx.Button(self, ID_R1B4, 'Grow', wx.Point(-1,-1), wx.Size(-1,-1))

         rs1.Add(self.r1b1, 0, wx.ALIGN_TOP)
         rs1.Add(r1b2, 0, wx.ALIGN_CENTER_VERTICAL)
         rs1.Add(r1b3, 0, wx.ALIGN_BOTTOM)
         rs1.Add(r1b4, 0, wx.EXPAND)

         self.Bind(wx.EVT_BUTTON, self.OnClick, id = ID_R1B1)
         self.Bind(wx.EVT_BUTTON, self.OnClick, id = ID_R1B2)
         self.Bind(wx.EVT_BUTTON, self.OnClick, id = ID_R1B3)
         self.Bind(wx.EVT_BUTTON, self.OnBob, r1b4)

         # -----------------------------------------------
         # Layout sizers
         self.sizer = bs
         self.sizer.Fit(self)
         self.SetAutoLayout(True)
         self.SetSizer(self.sizer)

     #
     # Event Handlers
     #
     def OnClick(self, event):
         # report button size
         bid = event.GetId()
         #btn = event.GetEventObject()

         # Size Button::GetDefaultSize()
         #bsize = event.GetSize()
         bsize = self.r1b1.GetSize()
         bwide = bsize.x
         bhigh = bsize.y

         message = 'Button %d is %d wide by %d high' % (bid, bwide, bhigh)

         # MessageDialog(parent, message, caption, flags, wx.Point(x,y)=defpos)
         dlg = wx.MessageDialog(self, message, 'MessageDialog', wx.OK)
         # Center puts dialog in center of screen, not center of window
         dlg.Center()
         dlg.ShowModal()
         dlg.Destroy()

     def OnBob(self, event):
         # report button size
         bid = event.GetId()
         #btn = event.GetEventObject()

         # Size Button::GetSize()

         #bsize = event.GetSize()
         bsize = r1b4.GetSize()
         bwide = bsize.x
         bhigh = bsize.y

         message = 'Button %d is %d wide by %d high' % (bid, bwide, bhigh)

         # MessageDialog(parent, message, caption, flags, wx.Point(x,y)=defpos)
         dlg = wx.MessageDialog(self, message, 'MessageDialog', wx.OK)
         # Center puts dialog in center of screen, not center of window
         dlg.Center()
         dlg.ShowModal()
         dlg.Destroy()
#
# end class Form1
#

app = wx.PySimpleApp(redirect = 1, filename = 'pyjim.txt')

frame = wx.Frame(None, -1, "Sizer Obstacle Course")

# add a Notebook to the frame
nb = wx.Notebook(frame, -1)

# add a Form1 to the notebook
form1 = Form1(nb, -1)

nb.AddPage(form1, 'Box Sizers')

frame.Show(1)

app.MainLoop()

# --------------------------------------------------
# jim.py - end of file
# -----------------------------------------------

A few comments for you:

Sorry for posting much code.

when you post a complete program, do as an attachment..mailers can mangle whitespace in various ways.

creating buttons: <<<<<<<<<<<<<<<<<<<<<<<<<<

self.r1b1 = wx.Button(self, ID_R1B1, 'Top', wx.Point(-1,-1), wx.Size(-1,-1))
r1b2 = wx.Button(self, ID_R1B2, 'Center', wx.Point(-1,-1), wx.Size(-1,-1))

The 'self' style is the only way I can get access to the button from within the event handler.

What is the difference between the two styles? (I realize that is a python objects question rather than a wxpython question.)

if you put it in self, you are creating a instance variable, that you can then access form other methods. I you don't need to access it in other methods, you can just create it as a local variable.

size and position with Sizers: <<<<<<<<<<<<<<<<<<<<<<<<<<
r1b2 = wx.Button(self, ID_R1B2, 'Center', wx.Point(-1,-1), wx.Size(-1,-1))
r1b2 = wx.Button(self, ID_R1B2, 'Center', (-1,-1), (-1,-1))
r1b2 = wx.Button(self, ID_R1B2, 'Center', 'pos(-1,-1)', wx.Size(-1,-1))

I am using the first style because that matches my reading of the method
signatures in the wxWindows doc. But elsewhere I see stuff that looks like the second or third approach.

See some of our discussion about DC methods....

Which is preferred?

I prefer the tuple, more Pythonesque.

Which is correct?

any of the above.

How can a vanilla tuple like (-1,-1)

stand in for a wx.Point or wx.Size? (Python is dynamically but strongly
typed).

because it's also polymorphic. An (x,y) tuple, or a wx.Point or a wx.Size are all sequences of two integers. Actually, it's probably really because Robin wrote the SWIG type maps so that an (x,y) tuple is converted to a wxPoint, which is just a very simple structure in C++.

Either way, it seems like an awful lot of typing just to say
'i am not specifying any values here'.

then leave them out, I think the defaults work fine. You can also use:

wx.DefaultSize and wx.DefaultPosition, which makes it very clear what you mean.

binding events: <<<<<<<<<<<<<<<<<<<<<<<<<<

self.Bind(wx.EVT_BUTTON, self.OnClick, id = ID_R1B3)
self.Bind(wx.EVT_BUTTON, self.OnBob, r1b4)

Again, I see both approaches in the demo or elsewhere. Which is preferred? Which is correct? What are the implications?

I like the later, as you don't need to hard code ids everywhere.

Neither approach seems to give the event handler access to the button though.

it won't make any difference to that. Have you tried:

wx.Event.GetEventObject()

I've never tried it, but it looks like what you want.

Generally, within a handler, the event argument seems to be a reference to the control that experienced the event.

No, it's a reference to a wx.Event

import os
import sys
sys.path.append('\Python23\Lib\site-packages\wx')

this should be required.. site-packages is on the path be default.

-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

Chris.Barker@noaa.gov

Jim Peterson wrote:

'''

Sorry for posting much code. this is my Wiki Obstacle Course
Fun With Sizers
program, cut down to the minimum to illustrate my questions/problems.

I want to bind my buttons to a common OnClick handler. The handler
should report the button size in a popup dialog.

Sounds simple but I do not see how to do it. I see varying code styles
but I do not get the nuances.

creating buttons: <<<<<<<<<<<<<<<<<<<<<<<<<<

self.r1b1 = wx.Button(self, ID_R1B1, 'Top', wx.Point(-1,-1), wx.Size(-1,-1))
r1b2 = wx.Button(self, ID_R1B2, 'Center', wx.Point(-1,-1), wx.Size(-1,-1))

The 'self' style is the only way I can get access to the button from within the event handler.

What is the difference between the two styles? (I realize that is a python objects question rather than a wxpython question.)

One stores a reference in the self object, the other throws it away.

size and position with Sizers: <<<<<<<<<<<<<<<<<<<<<<<<<<

r1b2 = wx.Button(self, ID_R1B2, 'Center', wx.Point(-1,-1), wx.Size(-1,-1))
r1b2 = wx.Button(self, ID_R1B2, 'Center', (-1,-1), (-1,-1))
r1b2 = wx.Button(self, ID_R1B2, 'Center', 'pos(-1,-1)', wx.Size(-1,-1))

The third one is incorrect.

I am using the first style because that matches my reading of the method
signatures in the wxWindows doc. But elsewhere I see stuff that looks like the second or third approach.

Which is preferred? Which is correct? How can a vanilla tuple like (-1,-1)
stand in for a wx.Point or wx.Size? (Python is dynamically but strongly
typed).

SWIG has a feature called typemaps that I use heavily in wxPython. When a function is called that is expecting a type that has a typemap then the code in the typemap is given an opportunity to convert the raw Python object into the expected type on the fly. For wx.Point, wx.Size and similar there is a typemap that can convert from any 2-element sequence of integers into the expected type. For wx.Colour it can take a 3-element sequence, a colour name defined in the wx.TheColourDataBase, or a string of the form "#RRGGBB". There are lots of other typemaps in use as well.

Either way, it seems like an awful lot of typing just to say
'i am not specifying any values here'.

binding events: <<<<<<<<<<<<<<<<<<<<<<<<<<

self.Bind(wx.EVT_BUTTON, self.OnClick, id = ID_R1B3)
self.Bind(wx.EVT_BUTTON, self.OnBob, r1b4)

Again, I see both approaches in the demo or elsewhere. Which is preferred? Which is correct? What are the implications?

They are equivallent. The second is more of a convenience though as it allows you to not have to track the ID of the event source yourself, Bind will figure out what the ID is all by itself.

Neither approach seems to give the event handler access to the button though.

They are not supposed to. You either need to save a reference to the object you need later in self, or if the object is the same as the source of the event then you can use event.GetEventObject() in the handler.

event handlers: <<<<<<<<<<<<<<<<<<<<<<<<<<

Generally, within a handler, the event argument seems to be a reference to the control that experienced the event.

No, it is an instance of a class specific to the type of event that was generated that carries the data specific to the event.

Certain functions that seem to attributes of controls rather than a wx.Event seem to be available.

I guess. But I cannot get wx.Button functions thru the event.

If I created the button as "self.mybutt=wx.Button(...)" I can reference
self.mybutt in the handler. But I am not able to access the control in any generic or unnamed way.

See above.

···

--
Robin Dunn
Software Craftsman
http://wxPython.org Java give you jitters? Relax with wxPython!