Creating the VerticalScrollbar class

Source File: 

Making some heavy decisions

Now we are going to start writing our class. We'll call it VerticalScrollbar. The first thing to do is to start making decisions about this class based on our best guess as to how we are going to use it, and if we are going to distribute it to others, how we expect that others might want to use it. Naturally, we want it to be as easy to use as possible.

This class can be written any number of different ways, but here's my vision for it: Users of our class ought to be able to create their own MovieClip instances for thumb, track, window, content, up, and down, then just make an instance of the class, sending it those things as arguments to the constructor. The thumb and the track will be required parameters, because without them, there is no scrollbar anyway. The window and content will both be optional parameters with default values of null. This will allow users of our class to create an instance and just use it as a Slider. Sometimes I've seen advice from others that you create a separate Slider class, and make it a property of the Scrollbar class, but I've decided against that. Our class will just do double duty, like I just described.

More optional parameters will be the up and down buttons. If they are supplied, the class will program them and define their behavior.

Another question is whether the scrollbar ought to itself be a display object (a display object container, actually). I have opted not to do this, because I see the class as just providing the behavior of a scrollbar, minus the baggage. When you send it all those objects as arguments, the class will just make them all behave like a scrollbar. The class will not actually itself be a scrollbar. That way, inside the class, issues like positioning the parts and adding them to its own display list need not be a consideration. And from the outside, instances of the class need not be positioned or added to the display list either. After all, the parts will already be positioned, and will already be on the display list anyway. The only possible advantage I can see to making the class itself a display object would be when showing and hiding the scrollbar, but we'll just make show() and hide() public methods to do those things anyway (EDIT: As you'll see later, I actually wound up doing this in a different, yet better, way--Jody).

Since it won't itself be a display object, the class will need to be sent a reference to the stage. This will appear as the first parameter.

So the parameter list will look like this (arranged, on purpose, in the order of most required):

VerticalScrollbar(stage, thumb, track, window=null, content=null, up=null, down=null)

Yet another question is whether the window and content ought to be incorporated into another Class that has an instance of the VerticalScrollbar class as a property. I have opted not to do this, but to just get it all done in one class, to make it easier to use.

The class is also going to need to dispatch some events, to accommodate the use of it as a Slider. Since it's not extending a display object, which would have given it event dispatching abilities, our class is going to need to extend the EventDispatcher class. The custom events that we'll make it dispatch will let us know (from the outside) when the thumb is pressed, when the thumb is released, and when the scrollbar is actively scrolling. We'll see how to dispatch these custom events from inside the class, and how to listen for them from the outside.

Another consideration is that the client code may need to access the scrollPercent property. Here I should say that this present tutorial owes a huge debt of gratitude to the Object Oriented Scrollbar tutorial by Lee Brimelow at gotoAndLearn.com. But in that tutorial, when it comes to accessing the scrollPercent, Lee shows how to create another separate custom class that extends the Event class, and how to send the scrollPercent as a property of that class, so as to access it in your event handler function. I highly recommend Lee's tutorial. However, I've decided that our class will just provide a public getter method for finding out the scrollPercent. So I've opted to not create a separate Event class. This just seems easier to me than creating a whole other class when I know that this is probably the only property I will need to access from the outside.

But without Lee's tutorial, this one wouldn't exist, and it was his tutorial that provided a milestone in my thinking about OOP, event dispatching, and things like "loose coupling." So, a thousand thanks, Lee!

Anyway, you can see I put a lot of thought into all of the above. These are all considerations where others might have a different opinion, and that doesn't bother me a bit. You are welcome to take off in your own direction and code it your own way. I'm just presenting how I did it, and why I did it that way, and I think I've got some good reasons. Here is our beginning basic framework for the class:

package com.jessamin.controls {
	import flash.display.DisplayObject;
	import flash.display.InteractiveObject;
	import flash.display.Sprite;
	import flash.display.Stage;
	import flash.events.EventDispatcher;
	
	public class VerticalScrollbar extends EventDispatcher {
		private var stage:Stage;
		private var thumb:InteractiveObject;
		private var track:DisplayObject;
		private var window:DisplayObject;
		private var content:DisplayObject;
		private var up:InteractiveObject;
		private var down:InteractiveObject;
		
		
		public function VerticalScrollbar(  stage:Stage, 
											thumb:InteractiveObject, 
											track:InteractiveObject, 
											window:DisplayObject = null,
											content:DisplayObject = null,
											up:InteractiveObject = null, 
											down:InteractiveObject = null  ) {
			this.stage    = stage;
			this.thumb    = thumb;
			this.track    = track;
			this.window   = window;
			this.content  = content;
			this.up       = up;
			this.down     = down;
		}
	}
}

Taking this line by line, the first thing to note is that this is going into a package at com.jessamin.controls (Jessamin Swearingen is a teacher friend of mine in NYC, and I just decided to use her website's name as an example package name).  If you are unfamiliar with packages and classpaths, you might want to read my tutorial Flash: The Big Picture. The import statements mostly just import the classes to support the several different types I used in the constructor (the exception is the one for EventDispatcher, which our class must import because it extends it). In the parameters list, everything is typed either as a display object or an interactive object. It's an interactive object if we are going to (potentially) allow user interaction with it (example: do you want the scrollbar to allow users to click on the track?). The variables list sets up private variables to match each of the items being passed in by the contructor.

The reason for using these more generic types instead of MovieClip, for example, is that the user of our class ought to be able to use a SimpleButton instance if they want to, for example. SimpleButtons are not MovieClips, but both MovieClip's and SimpleButtons are InteractiveObject's. So this way the parameter will accept a broader range of types and still work.

The first three items are required. The final four are optional, because they have an equals sign designating a default value of null. Later (that is, in the other functions in the class), we can test items to see if they still have a null value, so that we can tell whether to perform certain actions.

Now that we have the class's framework, we can start bringing in the code we developed on the timeline. A good workflow for this is to comment out all the code in the fla file, then write some new code there that makes an instance of the class instead. So turning our attention back to the fla file, go to the actions panel for frame 1. Click once in the actions panel so it has focus. Press CTRL-A to select everything there. Right click the selected code and choose "Apply /* */ Comment" from the context menu. This will comment out the whole block of code.

Select and copy this whole block of code again, but this time include the comment delimiters. Next, go to the window where you are writing the class, and paste it all in at the bottom. Because it's a comment in both places, it won't cause any problems in either one when testing. By keeping a copy of the code in both places, we have a safeguard against losing any of it should there be any crashes. After that, you just start transplanting the code from one place to another in the class, and testing, until eventually you get the whole thing working again. 

Next, returning to the actions panel, create some space by pressing Enter a couple of times at the top. Let's write an import statement and also create an instance of the class, passing it all the objects that are on the stage to its parameter list:

import com.jessamin.controls.*;
var scrollbar:VerticalScrollbar = new VerticalScrollbar(stage, thumb, track, window, content, up, down);

Press CTRL-Enter to test the movie. It should do... absolutely nothing! Because we haven't programmed it to yet! But we are just making sure we don't get any errors. On the next page, we'll continue adapting the timeline code to the class.