Published: April 18, 2007
By Richard G. Baldwin
Alice Programming Notes # 190
This tutorial lesson is part of a series designed to teach you how to program using the Alice programming environment under the assumption that you have no prior programming knowledge or experience.
Have some fun
Because Alice is an interactive graphics 3D programming environment, it is not only useful for learning how to program, Alice makes learning to program fun. Therefore, you should be sure to explore the many possibilities for being creative provided by Alice while you are learning to program using these tutorials. And above all have fun in the process of learning.
In the lesson titled "Lists" (see Resources) I taught you about the differences between an array and a list, including some of the pros and cons of each.
I compared the methods and functions belonging to a list with the methods and functions belonging to an array.
I presented and explained a simple program that illustrates most of the methods and functions belonging to a list.
I presented and explained a program that illustrates the use of the following tiles from the bottom of the Alice development screen:
In this lesson, I will teach you the general theory and practice behind interactive programming using events and event handlers. I will teach you about all of the event types supported by Alice. I will teach you how to enable events and how to register event handler methods on events. Finally, I will explain code samples that illustrate six of the thirteen available event types in Alice.
I recommend that you open another copy of this document in a separate browser window and use the following links to easily find and view the figures and listings while you are reading about them.
Once you have mastered Alice, I recommend that you also study the other lessons in my extensive collection of online programming tutorials. You will find a consolidated index at www.DickBaldwin.com.
Alice provides a rudimentary capability for using events to write interactive programs. While not nearly as flexible or as powerful as the capability provided by other languages such as Java and C#, this capability is entirely adequate for teaching the rudiments of interactive programming to beginning programming students.
An extremely important topic
Interactive programming using events is one of the most important topics in modern computer programming. Every program that you use on a daily basis that involves a Graphical User Interface (GUI) probably bases its interactive capability on the detection and handling of events. In fact, if you are less than about 23 years of age, you may never have seen a commercial program that isn't based on event handling.
What do we mean by interactive programming and handling events?
When you use a GUI, (such as the Alice development screen) to do your work, you constantly find yourself performing a variety of interactive operations, such as the following:
Similarly, when you play a computer game, you perform similar operations in the context of the game to cause the game to progress according to your wishes.
The firing of events
Each time you perform one of the actions mentioned above, (and many other actions as well), the operating system fires an event. In some cases, it fires a single event of a given type. In some cases it fires many events of different types, and in some cases it fires a sequence of one or more types of events, (such as when you hold a particular key down). The author of the program has the option of responding to all of the events that are fired, or responding to some of the events and ignoring others (very few programs respond to all of the events that are fired).
Handling an event
Writing code to respond to a particular event in order to cause the program to react in a particular way is known a handling the event. The code that is written to handle the event is commonly known as an event handler. That code usually consists of a method in Alice. (Some event types in Alice don't require methods as event handlers and we will see sample code for such an event type in this lesson.) The process of connecting the event handler method to the event is often referred to as registering the handler on the event or possibly enabling the event.
Events supported by Alice
Alice programs can respond to and handle the thirteen types of events shown in Figure 1.
Figure 1. Event types in Alice.
Event types in Alice
Note: Event types in boldface are illustrated by sample code in this lesson.
While this is a relatively small number of event types as compared to other programming languages, Alice supports enough different event types to make it useful for teaching the basics of interactive programming and event handling. Learning how to handle events in Alice will get you well on your way to being able to learn how to handle events in other languages.
Creating event handlers
You begin creating event handlers in Alice by making certain that the event editor pane shown in Figure 2 is showing. It should be visible in the upper right of the screen in program edit mode. (Sometimes it simply disappears for some unexplained reason and is replaced by a large black area. The only way that I have found to restore it in those cases is to terminate and restart Alice.)
Figure 2. Alice's event editor pane.
Registering event handlers
You begin the process of handling an individual event in Alice by clicking the button labeled create new event in Figure 2. (Note that clicking the button is another example of interacting with a program on the basis of events.)
When you click that button, the menu of available event types shown in Figure 3 will appear.
Figure 3. Selecting an event type in Alice.
When you select one of the menu items in Figure 3, skeleton code for enabling the event or registering a method on the event of the selected type will appear in the event edit pane as shown by the bottom block of code in Figure 4.
Where are the other event types?
Note that the menu shown in Figure 3 shows only nine types of events, but I told you that Alice can handle the thirteen types of events listed in Figure 1. For reasons that I am unable to explain, four of the event types shown in Figure 1 aren't available directly from the menu shown in Figure 3. To select the events in those four cases, you must:
That will cause the skeleton for the new type of event to replace the original skeleton. Items 1, 3, 5, and 7 in Figure 1 (each marked with an asterisk) identify the menu items in Figure 3 that must be selected to actually end up with items 2, 4, 6, and 8 in Figure 1.
Registration of a default event handler
When you create a new world in Alice and select the program edit screen, the registered event in Figure 4 named When the world starts will appear in the event edit pane by default. (Note that you can drag this event and drop it into the trash can if you don't need it.) As you will recall, a skeleton world-level method named my_first_method also appears in the code edit pane at that point. That method is registered on this event by default. (This is the method that I typically rename main to make it more consistent with Java, C++, and C#.)
Figure 4. A completed event and a skeleton event in Alice.
When you click the Play button
When you click the Play button in Alice and the program first starts running, an event of the type When the world starts occurs. This is a one-time event. It is never fired again during the execution of the program.
The default registered event handler
The registered event of the type named When the world starts shown in Figure 4 instructs the system to execute the world-level method named myfirstmethod when the event is fired. In other words, the method named my_first_method was registered by default to be called when the event named When the world starts occurs. This is the mechanism by which Alice connects events to the code that is written to handle them. (This mechanism is very similar to how events are registered and handled in Java. Note that some Alice event types do not require methods to be registered on them in order to enable the event. I will discuss this in more detail later.)
Conceivably you could also register other methods to be called and executed concurrently when that event occurs, but be careful about doing this. As I mentioned earlier, it is not difficult to stress the event handling and concurrent programming capability of Alice 2.0 beyond the breaking point, causing your program to fail for unexplainable reasons at runtime.
Skeleton event registration code
The bottom item in Figure 4 also shows the skeleton code for registering an event handler on the event type listed as item 4 in Figure 1 (While a key is pressed). To complete the registration of an event handler on this event, you need to replace the red text shown in Figure 4 with something else using typical drag-and-drop and menu-driven Alice programming procedures.
An actual matching registered event handler
For example, the fifth registered event handler from the top in Figure 2 shows the completed version of event registration for an event of this type in the program that I will explain later. In this program, whenever the D-key (upper or lower case) is pressed and held down while the program is running, the method named dance belonging to the object named dancer will be called repeatedly. (Unfortunately, I'm unaware of any Alice documentation that tells us how often the method will be called, but I have a pretty good idea based on many years of event-driven programming experience across a variety of languages.)
Three events under one event type name
The skeleton shown in Figure 4 actually makes it possible to register three different methods (although I only registered one method for that event type in Figure 2). One method is called when the key is first pressed (Begin). As mentioned above, a second method is called repeatedly while the key is held down (During). A third method is called when the key is released (End). If you don't specify the name of a method as a replacement for <None> no method is called when that particular event occurs. In other words, if you don't specify methods for events that require them, the event is essentially ignored by the program.
Several of the event types shown in Figure 1, including items 2, 4, 6, and 7, actually consist of Begin, During, and End events under the umbrella of a single event name. Therefore, the number of actual event types supported by Alice is greater than the thirteen event names shown in Figure 1.
The six registered events shown in Figure 2 are the actual registered events that I will explain in the program named Alice0190a. They correspond to the boldface event types shown in Figure 1.
Mouse icons and a documentation problem
Note that the event types shown in Figure 2 that involve the mouse contain a picture of the mouse instead of the word mouse. This probably seemed like a clever idea by someone at the time the Alice program was written, but in retrospect it was a bad idea.
So where are we?
Hopefully you now understand some of the background information on interactive programming and event handling in general. You also know something about the procedures used to register event handlers on specific types of events or to enable specific types of events in Alice. Therefore, the time has come to quit talking in general terms and get down to cases with an actual interactive program.
I will present and explain one program named Alice0190a in this lesson. This program isn't intended to do anything useful other than to teach you how to write interactive event-driven programs. Hopefully you will be able to go forward with what you have learned in this lesson and write simple games and other kinds of simple interactive programs using Alice.
The program output shortly after startup
Figure 5 is a screen shot of the program output shortly after startup.
Figure 5. Output from the program named Alice0190a shortly after startup.
The coach does jumping jack exercises
The word Events that is barely showing across the screen in large letters in Figure 5 quickly fades away. Shortly thereafter, the Coach object in the left of the screen shot starts doing jumping jack exercises and continues doing them during the entire time that the program is running.
Dancing around the flag
If you press the D-key and hold it down, the Japanese dancer dances in a circle around the flagpole as shown in the screen shot of Figure 6. (Note that the coach is in the middle of one of his jumping jack exercises in Figure 6.)
Figure 6. FanDancer object dancing around the flag.
Dragging the beach chair
If you point to the beach chair with the mouse and then press and hold either the left or right mouse button down, you can drag the beach chair around on the beach. Figure 7 shows the result of dragging the beach chair from right to left and toward the foreground.
Figure 7. The BeachChair object has been dragged to the left foreground.
This is a very significant capability that would require quite a lot of programming to accomplish if you were to program it in Java3D, because the beach chair maintains the 3D perspective while it is being dragged.
An unplanned capability
Although I didn't knowingly do anything to make it happen, I discovered quite by accident that this program provides a bonus capability associated with the mouse wheel on my mouse. If I point to any object in Figure 7 and then press and hold the mouse wheel down, dragging the mouse rotates the object around its vertical axis. However, because I have found that the behavior of the mouse wheel varies widely on different computers running under Windows XP, (which probably has something to do with how you configure the mouse, the brand of the mouse, etc.) I don't know if this is consistent behavior for Alice on different computers.
Dragging the flag
Just like the beach chair, you can drag the flag around the screen with the mouse. The interesting thing about this is that if you move the flag and then hold down the D-key, the dancer will initially begin dancing in a larger circle but will eventually spiral in and resume dancing around the flagpole in a circle with a radius of one meter. Also if you move the flagpole while she is dancing, she will try to track the flagpole. You will see the reason for this when I explain the event handling code for the dancer. This is illustrated by the screen shots shown in Figure 8 and Figure 9.
In Figure 8, the flag was moved from its original position, causing the dancer to dance in a circle with a large radius with the flag at the center of the circle.
Figure 8. Dancer at some distance from the flag.
Spiraling back toward the flagpole
In Figure 9, the dancer has spiraled back in and is once again dancing around the flag in a circle with a radius that is very lose to one meter centered on the flagpole.
Figure 9. Dancer back close to the flag.
Clicking the hare
Figure 10 shows the result of clicking the hare. Although you can't tell it by looking at Figure 10, in addition to displaying the comic strip bubble above the hare's head, clicking the hare with the mouse also causes the blades on the fan to start spinning. They continue spinning until you click the hare again as shown in Figure 11.
Figure 10. Result of a mouse click on the Hare object.
Turn fan off
Figure 11 shows the result of a second mouse click on the hare.
Figure 11. Result of a second mouse click on the Hare object.
In other words, successively clicking the mouse on the hare causes the messages shown in Figure 10 and Figure 11 to be displayed and also causes the blades on the fan to first start spinning and then to stop spinning.
Time for some code
Now that you understand the general behavior of this program, it is time for us to examine the code that produces that behavior. Note that I will concentrate on the event registration and event handling aspects of the code rather than the detailed code inside the event handler methods. You should already understand most of the code inside the event handler methods.
The source code
The source code for this program is shown in Listing 9. In addition to the word mouse being missing from the code as explained earlier, there is something else that is missing as well. In particular, in order for this program to work properly, it is necessary for you to manually create an empty list named moveableObjects as a property of the world. However, this is not reflected in the source code in the same way that lists are shown when they belong to methods. In fact, if I had manually populated that list when I created it, there would be nothing whatsoever in the source code to tell you that it exists and the nature of its contents.
Because I manually created it as an empty list and populated it with program code, an experienced programmer might be able to figure out what is going on. However, that would probably be well beyond the capabilities of a beginning programming student.
Create your world
Create a new world and select the sand template option. Add one each of the following objects from the local gallery to the world and give them the names shown below:
Add an empty list to the properties pane for the world and name it moveableObjects.
Don't worry about the position or orientation of any of the objects in the above list. The code in the method named doSetup will take care of the position and orientation of each object at program startup.
As mentioned earlier, the source code for this program is presented in Listing 9 near the end of the lesson. An executable version of the program can be downloaded by following the links in Resources.
The Events section of the code
With two exceptions, the code in the Events section of Listing 9 reflects the information shown in the event edit panel of Figure 2. The two exceptions are:
The two world events
Note that the first two registered events in Figure 2 are named:
As you can see, I wrote code to handle the first of the two above events, as well as the Begin and During phases of the second of the two events. This may be a bad practice unless you are very careful. In effect, the Begin phase of While the world is running is a replacement for When the world starts.
In theory, you should probably never need to register a different method on both. You should be able to accomplish the same thing by registering a single method on the either the first event or on the Begin phase of the second event. In fact, this may be the explanation for why four of the event types shown in Figure 1 are missing from the menu shown in Figure 3. This may be a message from the Alice development team that we should handle one, but not both of the events in each pair of event types in the first eight event types in Figure 1.
Why did I handle both?
I handled both events simply to illustrate this point. When we examine the code, you will see that I was very careful to make certain that the code in the two methods that will be called and executed currently will not conflict. In particular, the code in the main method and the code in the doSetup method, (which will execute concurrently), does not deal with the same objects.
The main method
In addition to referring to the code in Listing 9, in some cases, I will also present and discuss the program code in fragments. The code for the main method is shown in Listing 1.
Listing 1. The main method.
As you can see, the code in the main method deals only with the 3D text object that appears and then fades away when the program starts running. I was careful not to deal with the 3D text object in the doSetup method that is shown in Listing 2.
Beginning of the doSetup method
The method named doSetup begins in Listing 2.
Listing 2. Beginning of the doSetup method.
You should already be familiar not only with the code in Listing 2, but also with the reasons for providing the code shown in Listing 2. If not, see the lessons on setting the stage in Resources.
Position and pose the players
The code in Listing 3 puts each object into its startup position, orientation, and pose.
Listing 3. Position and pose the players.
|// Position and pose the players.|
|coach .move( RIGHT , 4 meters ); duration = 0 seconds|
|coach .move( BACKWARD , 4 meters ); duration = 0 seconds|
|beachChair .move( LEFT , 4 meters ); duration = 0 seconds|
|beachChair .move( BACKWARD , 4 meters ); duration = 0 seconds|
|hare .move( LEFT , 1 meter ); duration = 0 seconds|
|hare .move( FORWARD , 3 meters ); duration = 0 seconds|
|fan.spin .set( value , false );|
|fan .move( LEFT , 1.5 meters ); duration = 0 seconds|
|fan .move( FORWARD , 3.5 meters ); duration = 0 seconds|
|fan .turn( LEFT , .45 revolutions );|
|dancer .move( BACKWARD , 1 meter ); duration = 0 seconds|
|startUpText .move( FORWARD , 1 meter ); duration = 0 seconds|
Probably the only thing worth mentioning in Listing 3 is the statement that sets the spin property of the fan to false. The blades on the fan spin whenever this property is true, so the property value needs to be false when the program starts running so that the fan won't be spinning.
The ability to drag the beach chair and the flag with the mouse results from enabling the event named Let the mouse move (item 10 in Figure 1) as the third event down from the top in Figure 2. Unlike many other event types, it is not necessary to register a method in order to enable this event. Rather, what is required is to identify a list that contains one or more objects that can be moved by dragging them with the mouse.
The third event down from the top in Figure 2 specifies a list named world.moveableObjects for this purpose. You created that list as an empty list earlier during the manual setup.
Populate the list
Listing 4 adds the beachChair object and the flagPole object to that list, making them capable of being dragged with the mouse.
Listing 4. Populating the list with objects that can be dragged with the mouse.
Make objects visible
Up to this point, all of the activities of the objects have been invisible to the user and only a blue screen has been showing. All of the objects have been properly positioned and oriented, and all of the objects other than the coach have been posed. The code in Listing 5 makes all of the objects visible.
Listing 5. Make objects visible and show coach lowering his arms.
Cause the coach to lower his arms
When the Coach object is created from the gallery and added to the world, he has his arms outstretched on each side of his body. I decided to make that a part of the visible animation and let the viewer see him lower his arms to his sides before beginning his exercises. The call to the method named coach.lowerArms in Listing 5 accomplishes that. You can view that method in Listing 9. The code in the method is almost trivial by this point in the course of study, so it shouldn't need an explanation.
Coach does his exercises
That gets us through the explanation of the code through the Begin phase of the event named While the world is running in Figure 2. The next thing of interest is the method that is registered on the During phase of that same event type. During the entire time that the program is running, the method named coach.doJumpingJack is repeatedly called. Thus, the behavior of that method is evidenced during the entire running of the program.
The behavior of the coach.doJumpingJack method is to cause the coach in Figure 5 to do jumping jack exercises. You can view the method named coach.doJumpingJack in Listing 9. Each time the method is called, the coach object performs one cycle of a jumping jack exercise. Thus repeated calls to the method causes the coach to do one cycle after another producing the impression of continuous jumping jack exercises.
Although the code in the coach.doJumpingJack method is rather long and tedious, it doesn't contain anything that you haven't already learned in earlier lessons. Therefore, it should not require an explanation.
That completes the registration operation on the first two event types in Figure 2. In addition, I have already explained how the third event type in Figure 2 becomes enabled, so I don't need to say any more about that.
When the mouse is clicked on the hare
The fourth event registration operation shown in Figure 2 causes the method named hare.clickHandler to be called each time the mouse is clicked on the hare shown in Figure 10 and Figure 11. The code for this method is shown in Listing 6.
Listing 6. The hare.clickHandler method.
With a couple of exceptions, the code in Listing 6 is straightforward. Those exceptions have to do with the two statements that set the value of the spin property belonging to the fan object. As you will see later when I explain the last event registration block in Figure 2, the state of this property determines whether the fan blades spin or don't spin. If the property value is true, the blades spin. Otherwise, they don't spin.
Successively clicking the hare toggles the state of this property between true and false, thus controlling whether or not the fan blades spin.
The code in Listing 6 also displays the two messages shown in Figure 10 and Figure 11. You are already familiar with the effect of calling the method named say on an object.
While D is pressed
The fifth event registration block down from the top in Figure 2 causes the method named dancer.dance to be called repeatedly while the D-key (upper or lower case) is pressed and held down. This results from the fact that I registered that method on the During phase of that event type. Note, however, that I didn't register any methods on either the Begin or End phases of that event type simply because there was no special behavior that was needed at the points in time when the user first presses and later releases the key.
Source code for the method named dancer.dance
The source code for this method is shown in Listing 7.
Listing 7. Source code for the method named dancer.dance.
Circle up the wagons
You learned how to make one object circle and face another object in an earlier lesson, so the final two statements in Listing 7 should not require an explanation. However, the statements before that probably do deserve an explanation.
The distance to the flagpole
When you use code such as the final statement in Listing 7 to cause one object to circle another object, by default the radius of the circle will be the distance between the two objects when the statement is executed. In this case, I wanted the dancer to circle the flagpole at a distance of one meter from the flagpole.
Recall, however, that it is possible to drag the flagpole with the mouse and increase or decrease the distance between the flagpole and the dancer. This can be done while the dancer is dancing, or while the dancer is at rest.
Repeatedly circle the flagpole
The last statement in Listing 7 causes the dancer to complete one revolution around the flagpole each time the method is called. Because the type of event on which this method is registered causes the method to be called repeatedly while the D-key is held down, the effect is to cause the dancer to circle the flagpole continuously while the D-key is held down.
Calculate the distance to and spiral toward or away from the flagpole
Each time the method is called, the first statement in Listing 7 calculates the distance from the dancer to the flagpole. The first statement inside the doTogether block in Listing 7 causes the dancer to move toward or away from the flagpole (a negative distance causes a move away from) by a distance that will place the dancer at a distance of one meter from the flagpole. As a result, if you move the flagpole some distance away from the dancer and hold the D-key down, she will spiral in toward the flagpole and after a few revolutions will be circling the flagpole at a distance of about one meter from the flagpole.
If you move the flagpole and hold the D-key down at the same time, she will attempt to track the flagpole and may or may not be successful, depending on how fast you are moving the flagpole. An interesting experiment is to hold the D-key down and try to place the flagpole at the same location as the dancer.
While fan.spin is true
The last event shown in Figure 2 causes the fan blades to spin whenever the property named spin belonging to the fan is true. As I explained earlier, successively clicking the hare causes this property value to toggle between true and false.
This behavior of the fan is controlled by the last event registration block in Figure 2. As with all but one of the events that I handled in this program, this event type requires the registration of from one to three event handler methods. In this case, the behavior that I wanted to see could be achieved simply by registering one of the primitive methods belonging to the fan, and it was not necessary for me to write a special event handler method. Listing 8 shows the registration of the roll method on the During phase of the While fan.spin is true event type.
Listing 8. Registration of the roll method on the While fan.spin is true event type.
As a result of the code in Listing 8, the roll method belonging to the fan will be called repeatedly during any periods that the value of the fan.spin property is true. Each call to the method causes the fan blades to spin through one revolution. Repeatedly calling the method causes it to appear that the fan blades are spinning continuously.
An executable version of the program that I explained in this lesson is available for downloading (see Resources). I encourage you to either download the program, or copy the code from Listing 9 into your Alice development environment and run the program. Experiment with the code, making changes, and observing the results of your changes. Above all, have fun in the process.
In this lesson, I taught you about the general theory and practice behind interactive programming using events and event handlers. I provided a brief explanation of all the event types supported by Alice. I explained how to enable events and how to register event handler methods on events using the event edit panel. I presented and explained code samples to illustrate six of the thirteen available event types in Alice.
In future lessons I will teach you about the following topics and perhaps some other topics as well:
So stay tuned. There will be lots of fun ahead.
Resources from earlier lessons in the series titled "Learn to Program using Alice"
Listing 9. Source code for the program named Alice0190a.
Created by: Dick Baldwin
Copyright 2007, Richard G. Baldwin. Faculty and staff of public and private non-profit educational institutions are granted a license to reproduce and to use this material for purposes consistent with the teaching process. This license does not extend to commercial ventures. Otherwise, reproduction in whole or in part in any form or medium without express written permission from Richard Baldwin is prohibited.
Richard has participated in numerous consulting projects and he frequently provides onsite training at the high-tech companies located in and around Austin, Texas. He is the author of Baldwin's Programming Tutorials, which have gained a worldwide following among experienced and aspiring programmers. He has also published articles in JavaPro magazine.
In addition to his programming expertise, Richard has many years of practical experience in Digital Signal Processing (DSP). His first job after he earned his Bachelor's degree was doing DSP in the Seismic Research Department of Texas Instruments. (TI is still a world leader in DSP.) In the following years, he applied his programming and DSP expertise to other interesting areas including sonar and underwater acoustics.
Richard holds an MSEE degree from Southern Methodist University and has many years of experience in the application of computer technology to real-world problems.