[Pythonmac-SIG] Buttons in W

Corran Webster cwebster@nevada.edu
Fri, 23 Mar 2001 11:22:23 -0800


At 5:44 PM +0100 23/3/01, Fran=E7ois Granger wrote:
>This is my first attempt at using the W module.

If you haven't already discovered it, you may find my tutorial on W usefu=
l:

http://www.nevada.edu/~cwebster/Python/WWidgets/index.html

In particular, you may find some of the tricks used in the calculator=20
example to be helpful, as there are some common features with what=20
you want to do:

http://www.nevada.edu/~cwebster/Python/WWidgets/calculator.html

>As an exercise, I am trying to program the game "TicTacToe".
>
>My idea is to do a set of identical buttons in 3 row by three=20
>column. My problem is to write a call back function for all these=20
>button wich can detect wich one was clicked.
>
>some ugly code below, thanks for any input.

[snip]

>Token =3D 'O'
>def bpCase():
>	"""
>	handle the click on one location
>	"""
>	for i in range(3):
>		for j in range(3):
>			# here i need to get i,j when that is the=20
>button just clicked.
>			print w[i, j]._activated
>			if w[i, j]._activated:
>				print i,j
>				b =3D i,j
>	# here i will use b for other purposes
>	w[b]._title =3D token

Your problem seems to be determining which button was clicked from=20
within the callback.  Probably the easiest way to deal with this is=20
to do the following:

def bpCase(i, j):
     global Token
     button =3D w[i,j]
     # do stuff with button:
     button.settitle(Token)  # show either "X" or "O"
     button.enable(0)        # make the button unclickable from now on
     # do stuff related to the game
     if Token =3D=3D "X":
         Token =3D "O"
     else:
         Token =3D "X"
     # some code to determine if we have a winner - maybe calling out to =
a
     # class holding game state or a function which checks for wins or dr=
aws.
     # You'll need to write this.

You then need to use a lambda with default arguments which calls=20
bpCase for your callback for each button:

>stepb =3D 16
>for i in range(3):
>	for j in range(3):
>		w[i,j] =3D W.Button((20 + i * stepb,20 + j *=20
>stepb,stepb,stepb), "X", bpCase)

The creation line then looks something like:

                 w[i,j] =3D W.Button((20 + i * stepb,20 + j * stepb,stepb=
,stepb),
                     "", lambda i=3Di, j=3Dj: bpCase(i,j))

Notice the magic "lambda i=3Di, j=3Dj: bpCase(i,j)" which makes the=20
callback know which button it is associated with.

As written, the above code allows two humans to play, but doesn't=20
determine a winner.  Once a button is clicked, it is disabled and is=20
greyed out.  A slightly better approach would be the following:

def bpCase(i, j):
     global Token
     button =3D w[i,j]
     # do stuff with button:
     if button.gettitle():
         return
     button.settitle(Token)  # show either "X" or "O"
     # do stuff related to the game
     if Token =3D=3D "X":
         Token =3D "O"
     else:
         Token =3D "X"
     # some code to determine if we have a winner - maybe calling out to =
a
     # class holding game state or a function which checks for wins or dr=
aws.
     # You'll need to write this.

A more elegant solution would probably be to subclass W.Button,=20
rather than using callbacks.  You would override the click() (and=20
possibly the push()) methods to do what you would normally do in the=20
callback, but now you don't have to worry about finding your button,=20
as it is available as "self".  This also allows a more elegent=20
solution to the disabling of the button - simply ignore clicks are=20
the state has been set.

Regards,
Corran