Now that you have a basic understanding of what a MIAW is and why you might want to use one, let's add the necessary buttons and code to the training log in order to implement the graph.
Opening the Window
The first thing you need to do is add some buttons to the interface so that the graph can be opened whenever it's needed. Because the showMonth method within the graph accepts a B, R, or W, depending on the data being graphed, you'll need a way to specify the character. The easiest way is to add three different buttons to the training log interface, each one telling the graph to show different data for the montheither Biking, Running, or Walking.
Open the training log mytrainer from your project_two folder. (You can open myTRainer_start from the Lesson09 folder on the CD if you don't have your version handy.) Import the six button files from the Lesson09\media folder on the CD, importing the buttons into the internal cast.
Remember, when importing multiple images, you can choose Same settings for remaining images in the Image options dialog to make the import go quicker.
Once the button images have been imported, you can place them on the interface and then make them work.
In the Score, select channel 144 of frame 30. Next, drag the white versions of the three buttons onto the interface as shown.
Recall that you created the button rollover behavior previously, to enable the previous and next month buttons to work. The rollover behavior figures out what cast member to use for the rollover, by appending "_hi" onto the name of the normal cast member. Because the buttons are named appropriately, the rollover behavior will work perfectly with these new buttons as well.
Select all three button sprites, in channels 144, 145, and 146, then drag the button rollover behavior from the scripts cast and drop it onto the selected sprites.
Next, the buttons need a behavior attached that will create and open the graph window, and then draw the appropriate graph, depending on which button was pressed.
If the Sprite toolbar in the Score isn't showing, right-click the frame bar and select Sprite Toolbar. Next, click the B button to select it, and choose New Behavior from the script drop-down menu, as shown.
Note that because the script cast was active, the new script is placed into that castright where it belongs.
Modify the default mouseUp behavior to make it appear like the following:
on mouseUp me window().new("graph") window("graph").movie.showMonth("B") window("graph").open() end
First, a new window is created named graph. Because the graph movie exists in the same folder as the main movie, the movie is automatically loaded into the window. Next, using the new DOM structure, you call the showMonth() method within the graph movie, sending it the "B" character, which displays the graph for biking that month. After the graph is displayed, the window is opened. If you were to open the window before calling showData() the graph could appear blank for a second before showData() was called.
Let's try out the code and see how it works.
Name the script open graph b and close the Script window. Rewind and play the movie. When the calendar appears, press the B button to graph the month's biking data. What happened? Instead of the graph appearing in the window, the window remains blank, while the graph draws right over the calendarnot at all what you expected! The reason for this is that within the graph movie you're using the following code to draw with:
When using MIAWs, the Stage will always refer to the main movie, namely the Stage movie, which opens the window. When creating movies that will be used as MIAWs you'll need to plan accordingly, and target the proper window. Let's add the behaviors to the R and W buttons, and then modify the graph movie.
Select the W button and choose New behavior from the behavior drop-down in the sprite tool bar. Modify the mouseDown script so it appears as follows:
on mouseUp me window().new("graph") window("graph").movie.showMonth("W") window("graph").open() end
Name the script open graph w and close the script window. Select the R button and choose New Behavior from the behavior drop-down. Modify the mouseUp behavior to be as follows:
on mouseUp me window().new("graph") window("graph").movie.showMonth("R") window("graph").open() end
While you could have created a getPropertyDescriptionList handler and used the same behavior for each of the three buttons, it's quicker to make three separate scripts. Depending on the project, you will find creating a GPDL to be more efficient, while at other times it's more work than necessary.
Close the script window and save the movie.
You can now modify the graph movie so that it works properly when used as a movie in a window.
Targeting the Window
As you saw in the last section, it's important to target the proper window when designing movies that will be run as MIAWs. To do this effectively just requires a little planning and foresight.
You could open the graph movie, then use the find and replace feature to simply replace all occurrences of _movie.stage with window("graph"), and everything would run properly. But if you do that, the graph movie will only run as a MIAW, making it much more difficult to do testing with. The solution is to check and see if the movie is running as a MIAW. If it is, you use the window("graph") code. If it's not, you use the _movie.stage code. This way, you'll get the best of both worlds and the graph will run whether you're running it alone during testing, or running it in a window from the main application.
To target the proper window, you will use the player object's windowList property. The windowList is just thata list of all running windows. Need to know if the graph is running as a window? Check to see if the graph window is active in the windowList. If it is, the movie is running in a window; it's that simple. Examine the following output from the Message window:
trace(_player.windowList) -- [(window "stage"), (window "graph")]
As you can see, there is both a Stage window and a window named graph. To check if the graph window is in the list, you can use the getOne method available to lists. The getOne method will return the index of the item in the list, or it will return zero if the item is not in the list. For example:
trace(_player.windowList.getOne(window("graph"))) -- 2
This is telling you that the window named graph is the second item in the list.
trace(_player.windowList.getOne(window("taco"))) -- 0
The window named taco isn't active, so the result is zero.
Note that you used _movie.stage in the graphing code to draw onto the Stage. However, the windowList shows a window named stage. Either method is acceptable to use, as you will see in a moment.
From your project_two folder, open the graph movie, then double-click the Main Script to open it for editing.
Within the display method you need to change the _movie.stage references to be either the stage or the graph window as appropriate. While you could add an if statement each time you need to draw into the graph, it would be better to use a local variable at the start of the method and assign the proper window to the variable. Something like this would work fine:
if _player.windowList.getOne(window("graph")) <> 0 then myWin = window("graph") else myWin = window("stage") end if
However, there's an even better way that does not require a conditional test, and will also work if the movie is playing normally or as a MIAW. The Player object's activeWindow property will return the Stage when the movie is running alone, or it will return the window when the movie is running as a MIAW.
All you need to do then is replace all the occurrences of _window.stage with _player.activeWindow and the graph will function properly running on its own or in a window.
Press Ctrl/Command+F to open the Find Text dialog box. Enter _movie.stage in the Find field and enter _player.activeWindow in the Replace field. Make sure to search just the current script (cast member 8) and then click the Replace All button. Click OK in the alert that follows.
Just like that, all occurrences of _movie.stage have been replaced with _player.activeWindow, and the graph will work as expected.
Close the script window, then rewind and play the movie. Open the Message window and enter showMonth("B") to display the biking data for the current month.
Assuming that the global variables theMonth and theYear both have data in them from running the main movie, you should see the graph displayed. If not, use the Message window to set theMonth and theYear to appropriate values, then repeat step 3.
Before returning to the training log, let's take a moment to discuss the startMovie and stopMovie handlers.
on startMovie _global.myDB = new(xtra "arca") _global.myDB.openDB(_movie.path & "exercise") end on stopMovie _global.myDB.closeDB() end
The problem is that whenever the graph movie is run, the startMovie handler runs and the exercise database is opened. This is fine when the graph is running alone, and actually necessaryotherwise you wouldn't be able to select any data. When the movie is running in a window, the database is opened by the main application. However, trying to open a database that is already open will fail silently and not produce an error. While that's bad practice, no real harm will come of it. The real problem is in the stopMovie handler. Here, the database is closed when the movie is stopped. Because a MIAW can be stopped by the main movie, closing the database could definitely be an issue.
The best solution is to add a check to both handlers and only open or close the database if the movie is running alone and not in a window. To do this you can again make use of the activeWindow property by seeing if it returns the stage window.
Open the Main Script and add a test to the startMovie handler so that it appears as follows:
on startMovie if _player.activeWindow = window("stage") then _global.myDB = new(xtra "arca") _global.myDB.openDB(_movie.path & "exercise") end if end
Now the database will be opened only if the graph movie is the main movie being executed.
Add the same conditional test to the stopMovie handler so it appears as follows:
on stopMovie if _player.activeWindow = window("stage") then _global.myDB.closeDB() end if end
The graph movie is now properly set up to be run as both a MIAW and a standalone for testing.
Save the movie, then open the myTRainer movie. Play the movie and click the B button to graph the biking data.
The graph now properly appears in the graph window, instead of over the calendar. You can drag the graph outside the Stage boundaries by clicking in its title bar, and you can close the window using the close button. Except for some cleanup tasks, the graph MIAW is working well.
Click the next month button to get to a month that has no data entered. Click any of the graph buttons.
An error is generated and an alert box appears containing a rather cryptic message: Handler not found in object - #max. Is max the object or the handler?
Click the Script button.
Typically, the script button would open a script window and bring you to the line of Lingo that produced the error. But here, the script window is blank. This is because the script the produced the error is in the graph movie.
Stop and save the movie before continuing.