Creating a Complete PythonCard Application from Scratch
by Dan Shafer (firstname.lastname@example.org)
This is the second in a series of PythonCard walk-through documents. It assumes you have either read and worked your way through PythonCard Walk-Through No. 1 which teaches you the basics of working in the PythonCard environment or that you already understand those basics.
Purpose and Scope
The purpose of this walk-through is to walk you, step by step, through the process of creating a PythonCard application. By the time you have finished this walk-through, you will:
- understand how PythonCard's GUI building facilities work
- know how to create a starting point for a new PythonCard application
- have a grasp of the basic event-handling architecture that gives PythonCard applications life
- know how to create menus and menu items in PythonCard and to hook those items up to actions
Over the years as I've played with various GUI tools and development environments, I have traditionally created a simple counter application as a way of getting familiar with the tool's basic operation and gaining some nodding acquaintance with its language and architecture/API. When PythonCard appeared in my life courtesy of my old colleague Kevin Altis, I decided that I should do the same. Kevin encouraged me to document my efforts and this is the result.
This document walks you step by step through the process of creating an intentionally simplistic PythonCard application. I don't claim that this is the best way to accomplish this objective, let alone the only one. It just happens to be the way I approached it. At the end of this tutorial, I will make a few observations about other things that I could have done that would make the example more instructive or interesting. Note that this tutorial describes how this process is handled in PythonCard 0.8.2. Continuing enhancements to the UI, especially in the resourceEditor, will make the process more and more streamlined over time.
This simple application, the finished result of which is shown in Figure 1, consists of three buttons and a text field. The text field holds a numeric value (represented as a string) which is manipulated by the three buttons. The buttons add 1 to the current value displayed in the field, subtract 1 from that field's value, and reset the field's value to 0.
Figure 1. Finished Counter Walk-Through Application
The Application Creation Process
Creating an application in PythonCard begins with the creation of a basic structure. There are two ways to do this. One is to use the PythonCard Resource Editor (called resourceEditor.py), start with the basic empty window, and code from scratch. The other is to copy an existing application's folder, rename a few basic things, and begin with a somewhat more complete starting point. I'm taking the latter course here.
The process in summary
- Run resourceEditor to create or modify an existing application.
- Lay out the application's window in Resource Editor.
- Script the components that will trigger actions (buttons and/or menus)
- Cleaning up artifacts of the copied program.
Let's go through those steps with my simple Counter tutorial.
A. Run resourceEditor to modify an existing application.
- Make a copy of the "minimal" project folder in the samples folder of the PythonCard distribution. Put into its own folder called "counter." (The folder name isn't important to PythonCard.)
- Rename "minimal.py" to "counter.py" and " minimal.rsrc.py" to "counter.rsrc.py."
- Launch resourceEditor, which is found in the PythonCard distribution's tools folder
- Open the file counter.rsrc.py in the folder you just created. The window looks identical to the minimal application when it is running, except for the menu bar which remains the resourceEditor's menu bar since we are running resourceEditor at the moment) rather than the Counter application's menu bar. Figure 2 depicts this start-up situation. resourceEditor is a "live" editor; the GUI components of the application are running while you edit the window layout.
Figure 2. Startup Screen for Walk-Through Counter Application
B. Laying out the window for the counter tutorial application.
- Select the text field containing the words "Hello PythonCard" by clicking anywhere in it.
- In the Property Editor window, select the "text" property in the right-hand list of properties for the field1 Text Field object. Select the words in the field and delete them with the Backspace key.
- Type the number "42" (or some other number; I just happen to be a Douglas Adams fan) into the box.
- Click Update.
- In the Property Editor window, select the "font" property in the right-hand list of properties for the field1 Text Field object. Click on the "Font" button and set the font size to 24. [Note that there is a bug in the GTK version of wxPython 22.214.171.124 that prevents the font from being changed. This will be fixed in the next release of wxPython.]
- Click Update.
- Use the resize handles to shape the field so that the entire value "42" shows. Then position the field near the right edge of the window and approximately centered vertically. (You will probably need to resize the window itself; use the same technique for doing so on your system as you'd use for any window.)
- Select the "editable" property of the Text Field object called field1 and uncheck the checkbox. (By making the field read-only, we avoid the necessity of error-checking that would be required if we let the user enter a value directly into the field.)
- Click Update.
- Select Save from the File menu to save the counter.rsrc.py resource file.
- From the "Components" menu, select "Button"
- In the Property Editor window, select the "name" property in the right-hand list of properties for the Button1 Button object. Change the default name to incrBtn (for "increment button")
- Click Update.
- In the Property Editor window, select the "label" property in the right-hand list of properties for the incrBtn Button object. Change the label from Button1 to Increment.
- Click Update.
- Position this button in the upper left portion of the window.
- Repeat steps 11-15, but this time change the default name to decrBtn (for "decrement button" and the label from Button1 to Decrement. Remember to click the "Update" button in the Property Editor after setting each property.
- Position the Decrement button below the Increment button, approximately in the middle of the window.
- Repeat steps 11-15 one more time. Change the default 'name' to 'resetBtn' and the 'label' to 'Reset'.
- Position the Reset button to the bottom of the vertical row of three buttons.
- Save your work.
Your project should now look like Figure 3.
Figure 3. Project With Buttons Added
C. Scripting the Buttons
Application scripts are stored in the Python (.py) file that represents the application. In this case, that means they are in the file counter.py.
- Using PythonCard's built-in codeEditor or your favorite Python code editor, open the file counter.py. It is a small file with a self-explanatory comment and only one event-handling script right now (which responds to the user selecting Exit from the File menu). codeEditor is found in the tools directory of your PythonCard distribution.
- Delete the last line of the class definition, which currently says pass.
- Enter the following script, remembering that Python is white-space aware so that indentations of lines are significant. Since this is a definition of a method of the class, the first line will be indented, and subsequent lines will be indented twice.
def on_incrBtn_mouseClick(self, event): startValue = int(self.components.field1.text) endValue = startValue + 1 self.components.field1.text = str(endValue)
Let's examine this script because the others we will write are all but identical.
The opening line of a PythonCard event handler always starts with the keyword "def" which is standard Python for function and method definition. The next expression in the line starts with the PythonCard keyword "on_" and is followed by the name of the component we are scripting. In this case, it's the Increment Button, whose name is " incrBtn". After another connecting underscore, the last portion of the handler definition line defines the event for which this handler is to be called. All events take the same basic set of parameters as shown above.
The next lines are simple Python for the most part. The first line defines a variable called "startValue" to which we assign the current contents of the field, coerced to an integer so we can perform arithmetic on it. The second line adds one to the value we just retrieved. The third line assigns this new result to the field's text property after coercing it to a string.
- As long as we're in the application's main code file, let's also make our program a little more internally consistent. Change the name of the class we're creating from Minimal to Counter. At the end of the file, replace "Minimal" with "Counter" in the line that begins "app = ". The result should look like Figure 4.
Figure 4. Code Changes in counter.py
- Save your work.
- From the resourceEditor's File menu, select "Run."
- When the Counter application appears, click on the Increment button and watch the displayed value in the text field to confirm that it is incrementing as expected.
- Exit the application.
- Back in your Python Editor, copy the function we just created for the Increment button and paste it under that function, being sure indentation remains correct.
- Edit the new handler to change the name of the button from incrBtn to decrBtn and the '+' sign to a minus (' - ') sign.
- Create a final handler for the Reset button that looks like this:
def on_resetBtn_mouseClick(self, event): self.components.field1.text = "0"
Figure 5 shows you what your editor window should look like now.
Figure 5. Editor Showing Final Code Changes
- Save your work and test the application again to be sure it still works.
What if the application doesn't run? In that case, you can use the " Run with interpreter" command under the "File" menu to get a look at what errors, if any, are occurring. To see this in action, let's introduce a typographical error into counter.py. (You can skip this discussion if you either already know how to do this or are confident that you'll never create a PythonCard bug that will cause the programs to fail.)
- Open counter.py in your Python editor if it isn't already open.
- Change the word "class" to "classy" and save the program.
- Run the application as you have been doing. You will probably see a brief console window appear and then disappear. Nothing else happens.
- From the File menu in resourceEditor, choose "Run With Interpreter. " This launches your PythonCard application with the Python interpreter in a command console for your system so that you can see what error is being generated.
- You should see a syntax error indicated in the new window. It should be displaying the line where we created the intentional typo. (See Figure 6)
Figure 6. Error Shown in Console Window
- Press Ctrl-Z and Enter to terminate the Python interpreter and close the console window.
- Go back to the counter.py file and fix the line. Save the file and then re-run the application either from the resourceEditor's File menu or from the command line.
D. Cleaning up artifacts of the original program
We already took care of changing the class name and the runtime invocation name of the application from Minimal to Counter. Now let's change the resource file to reflect the program's new name.
In resourceEditor, go to the Edit menu and select "Background Info... " Change the name of the application to "PythonCard Counter" and click OK.
That ends the basic aspect of this second PythonCard walk-through. You now have a finished and working PythonCard application.
Optional Step: Adding a Menu
We'll add one optional step for a program like Counter, one which you may well need to take in any application of even a little greater complexity than this one. We'll add a menu to the application.
- In the resourceEditor, go to the Edit menu and choose "Menu Editor ..."
- A dialog box appears (see Figure 7) with the current menu structure displayed on the left. As you can see, the Counter application, which was started from the sample application called minimal., has a single menu with a single menu choice.
Figure 7. Opening Screen of Menu Editor
- Click on the "New Menu" button. You should see a dialog box like the one in Figure 8.
Figure 8. New Menu Item Dialog Box
- In the editing area to the right of the display showing the menu, change the name of the menu to menuCounterMenu and its label to Counter.
- Now click on "New Menu Item" and add a new menu item named "counterMenuIncrement". Make its label "Increment".
- Click on "New Menu Item" again and do the same for new menu items "Decrement" and "Reset". When you're done your work should look something like Figure 9.
Figure 9. Menu Editor With All Menu Items Defined
- Save your application in resourceEditor.
- Open the counter.py Python code file in your Python editor. Add the handler name shown here:
def on_counterMenuIncrement_select(self, event):
- Copy the three lines of the function in on_incrBtn_mouseClick and paste them into the definition of this menu function. (Be sure levels of indentation are consistent.)
- Follow the same procedure for hooking up the Decrement and Reset menu options. When you're finished, your code window should look something like Figure 10.
Figure 10. All Menu Items Programmed and Ready to Go
- Save your work.
(You'll notice that the new menu doesn't appear in your application in resourceEditor. Rest assured it will be there when you run the application outside resourceEditor.)
- Run the application (see Figure 11) and confirm everything works as expected.
Figure 11. Finished Counter Application With Counter Menu
(NOTE that it would obviously be better design to factor out the duplicated code into methods that handle the increment, decrement and reset buttons and menus as processes and then to call those methods from within the event handlers. We leave that you as an exercise for the reader. Don't you hate when we do that to you?)
$Revision: 1.15 $ : $Author: alextweedly $ : Last update $Date: 2006/04/06 11:00:25 $