It is time to complete the “Life” simulation, pushing on toward re-using parts of our program for other simulations.
During lab last week, you should have completed the changes to Grid.display() that allow you to pass it a “displayer” object, one version of which prints the grid, as before. That will be the main change that you make to life.py.
Your GUI interface goes in lifegui.py. Your “application” class should create a pair of frames in the root window, one for the controls and one for the grid. You should create a class for the GUI interface to the grid itself. Either this class or your application will need to support the “displayer” interface.
The displayed grid is most easily made as a collection of buttons; you can use class extension so that each button “knows” its location in the grid and has a handler method that calls the toggle method on the corresponding cell when clicked. Each can also have a StringVar as an instance variable so that it knows what to display. That StringVar will need to be updated after you toggle a cell and by the “displayer” showElement() method.
You can think of your program as having two layers: there is the underlying simulation in life.py, and the GUI interface in lifegui.py. That means that lifegui will need to import from life.
For running the simulation with a GUI, it is lifegui that will be the main program; so you’ll end up with something that you can run (at the shell prompt) with
The “main” function or object in lifegui will take care of creating a Grid as well as the GUI objects. For the most part, you’ll have methods/functions from lifegui calling down into methods/functions in life. The exception will be that Grid.display() will call methods on the “displayer” instance passed to it—which will likely be the only time that something in life calls anything in lifegui.
This layered structure makes it easier to keep track of responsibilities. The exceptional calls going in the reverse direction are sometimes described as callbacks or upcalls.
Once you have all of this working, there are several features you might want to add to your interface:
Any of these will involve learning more about
Sometimes you want to change an attribute of an widget after you have created it. You can do that by calling the config() method on the widget, giving it the same kinds of keyword arguments that you give when you create it. For example, If you have a label x, you could change its relief with
In addition to the attributes that were listed in Lab 9, you might find the following useful to change:
You can find more documentation about Tkinter at these three sites:
http://www.pythonware.com/library/tkinter/introduction/
http://effbot.org/tkinterbook/
http://infohost.nmt.edu/tcc/help/pubs/tkinter/
What is there is not complete, but does suggest things that you can do.
If you set up a “run” button, what you want is for that button’s action to cause the simulation to step over and over. You can’t just write a loop that calls step(), however, as that would not allow the display to update or respond to user actions. The way around this is to use the idea of a scheduled alarm. So you might end up with a method like this on your application class:
What the last line does is schedule another event (after delay milliseconds) that will call this method again.
That’s not quite everything you need: you probably want the “run” button to disable and enable various other controls, and you’ll need to have some way to make it stop. That’s a place for your creativity…
Sometimes you want to have a button pop-up a little window for further interaction; these windows are called dialogs. The easiest dialogs can be picked up from the tkMessageBox module, described under “Standard Dialogs” in the Tkinter documentation. An easy example, which just shows a message, would look like:
That just pops up a window and waits until the user hits “OK”.
You can get a little fancier with askyesno, which puts up two buttons, returning a boolean indicating the choice.
If you want to get a few inputs, you would use the tkSimpleDialog module, and make a class that extends tkSimpleDialog.Dialog. I’ll be making an example available.
Polish your program in life.py and lifegui.py. Write your reflections in life.txt.
Turn in a snapshot of where you are at the end of lab today, using
Turn in the final version before lab on next Thursday, using the same command.