Filed under Tips, Tricks, and Hacks

Using Abstract Classes in the Flash CS3/4 Library

by

Here’s a little trick that can help you save lots of time that might otherwise be spent creating multiple specialized classes in your Flash project. This trick makes use of the Base Class field in a symbol’s actionscript properties. (For info on creating pseudo-abstract classes in AS3, go here)

By the way, this tip may be common knowledge to Flash users. I use FlexBuilder almost exclusively these days but recently have had to dip back into the twisted world of the Flash IDE so please refrain from leaving any comments about how I shouldn’t use the timeline.

The Problem

Say you have several different buttons for a site that each look of behave slightly differently but all share the same underlying functionality. In this example, I’ll be using a crude set of video controls. I want each of these different controls to respond to rollovers by showing the label beneath the icon.

picture-1

Each  control has different icons and text so they’re going to need to be kept in different symbols. One solution might be to try to cram all the icons into one master symbol and change between the different icon frames using code. But that’s sloppy and unnecessary. Another solution might be to create 4 different classes that each implement the functionality or each extend a class with common functionality. This is a much better solution, but requires you to create 4 AS files for what functionally is just 1 type. You cannot use the same class for multiple symbols in your library though. Fortunately, Flash offers another solution that may be a bit less intuitive.

The Solution

If you needed to create the same sort of control components purely using code (using Flex for example), your first step would likely be to create some sort of base class that implements the common functionality of the 4 controls. Here’s an example of a base class for these 4 controls.

package {

	import flash.text.*;
	import flash.display.*;
	import flash.events.*;

	public class AbstractVideoControl extends MovieClip {
		// you'll need to create this text field on the timeline
		// and set the instance name to "label"
		public var label:TextField;

		public function AbstractVideoControl() {
			label.visible = false;
			addEventListener(MouseEvent.MOUSE_OVER, onMouseOver);
			addEventListener(MouseEvent.MOUSE_OUT, onMouseOut);
		}

		protected function onMouseOver(event:MouseEvent):void {
			label.visible = true;
		}

		protected function onMouseOut(event:MouseEvent):void {
			label.visible = false;
		}
	}
}

Note: In many non-ActionScript languages, there is a construct called an “abstract type” which  is simply a base class that cannot be instantiated on its own, only extended. In Flash, proper abstract types don’t exist, but we can consider a class Abstract if it shouldn’t be instantiated without being subclassed. More on that at Wikipedia.

Next, let’s make our controls extend this class. For each symbol, check the Export for ActionScript box in the symbol properties. Since Flash can automatically generate classes for symbols when an .as file doesn’t exist, the only thing you’ll need to fill in is the Base Class field (later, you can create a class for PlayButton if you need one). Make sure you use the fully qualified name if you’re using packages.

picture-3

Moar

I found this technique was very useful for when I wanted to animate TextFields on the timeline. Timeline animations, as you probably are aware, only work with MovieClip symbols. That means that even simple animations on text require the text to be contained in a symbol. I created an AbstractTextFieldWrapper class so that I could easily work with animated type without having to create new classes every time the format changes.

package {
	import flash.display.MovieClip;
	import flash.text.TextField;

	/**
	 * This class allows you to create an animated text field on the
	 * timeline and still set the text of the field without creating a new
	 * class for each text field that does this.
	 *
	 * @use In the flash library, create a new movieclip symbol containing the
	 * 		textField. Make sure you set the instance name for the text field to
	 * 		"textField". Make the base class for the symbol
	 * 		"AbstractTextFieldWrapper".
	 * 		In another class, use the type AbstractTextFieldWrapper insatead of
	 * 		TextField for your text field variable.
	 */
	public class AbstractTextFieldWrapper extends MovieClip
	{
		public var textField:TextField;
		public function set text(text:String):void {
			textField.text = text;
		}
		public function get text():String {
			return textField.text;
		}
	}
}
Tagged , , , ,

The quest for the elusive “N-gleton”

by

Sure, we’ve all heard of Singleton, the design pattern that limits the number of instances of a class to one. It’s a feel good pattern because it’s easy to use and make us feel smarter in front of our co-workers, even though some would argue that Singletons are just glorified global variables. But for a long time, I have wondered if it would be possible to use the same idea to limit the number of instances to two or more instead of just one. I called this hypothetical pattern an “N-gleton”, pronounced “en-gull-ton”. (UPDATE: Comments from readers inform me that this is called a “Multiton“) It may not be possible to make a poly-instance singleton, it may not be good programming practices, I’m not even sure I can think of a reason why it might be useful, but today, I tried my hand at inventing it and found something else entirely.

Continue reading

Q&A – is, as, and type conversion

by

A question from a reader gave me an excuse to write a huge rant about type conversions:

I’m doing a little exercise in a book that makes a textfield in which each letter can only be entered once. Not very useful, more of a teaching thing really. However there’s a bit of code that says:

var tf:TextField = event.target as TextField;

I don’t understand this at all! What the hell is event.target as TextField? Anyway here’s the full code for context’s sake:

package com.FoundationAS3.ch6 {

	import flash.display.Sprite;
	import flash.text.TextField;
	import flash.text.TextFieldType;
	import flash.events.TextEvent;

	public class PreventDefaultTest extends Sprite {

		public function PreventDefaultTest() {
			var tf:TextField = new TextField();
			addChild(tf);

			tf.width = stage.stageWidth;
			tf.height = stage.stageHeight;
			tf.type = TextFieldType.INPUT;
			tf.wordWrap = true;

			tf.addEventListener(TextEvent.TEXT_INPUT, onTextFieldTextInput);
		}

		private function onTextFieldTextInput(event:TextEvent):void {
			var tf:TextField = event.target as TextField;
			if (tf.text.indexOf(event.text) > -1) {
				event.preventDefault();
			}
		}
	}
}

Thanks,
-Neal

My response after the jump.
Continue reading

Tagged , , , , , , , ,

A website costs as much as a car

by

When people ask me how much it costs to make a website, my answer is always “A website costs as much as a car.” This invariably triggers the response “Oh, ok… Wait, what kind of car?”
“Exactly.”

A car can be many things. A new sedan, a used 1987 stationwagon, a hummer limo, a highly tuned race car, or a smart car with a 2-year lease are all examples of cars. They may range in price from a few hundred bucks to several hundred thousand or even a monthly fee or sometimes even free.

Websites are the same way. Based on the complexity, customization, features, and level of detail, a site can span the same range of prices. Many people decide that they want or need a website without asking the basic questions that help guide the process like “what is the goal of the site”. Quite often, the actual needs are very simple and generic solutions (such as a PayPal shopping cart) are ideal – the same way that a person commuting 10 miles to work needs a reliable but modest car to get them there and not a sports car (or sometimes it’s better to take public transit). I’ve found that describing the work in these terms tends to help potential customers to create more realistic expectations and reconsider their needs by presenting the concept of a website not as a fixed product but as a toolkit of solutions to specific business needs.

I’m not promising anything, but hopefully this has been the first entry in a short series on my work philosophies. Stay tuned!

Tagged , ,

Tip: Adding version checking to your external code library

by

Since version 1.0 of a code library that I’m sure you’re tired of me talking about came out, I have been making steady updates, some of which break legacy code. I was also having trouble keeping track of which version of the library a particular demo was written for. In order to make sure that the new code library doesn’t cause unpredictable results for the old implementations I added a version check to the main class.

This version check is very simple. It checks a version number in the client code against a version number of the library (or external classes) when the main class of the library is initialized. It is also completely optional (so average users don’t need to mark up their code with version numbers).

Here’s an example:

Say you normally initialize your library using:

MyLibrary.initialize();

Which calls the initialize method:

public static function initialize():void {
   // initialize library here
}

If the external code changes unexpectedly (say through an SVN update) this could cause problems that are difficult to trace. The solution is to modify the initializer to match the client code version with the initializer version.

public static const VERSION:String = "1.6";
public static function initialize(versionCheck:String = VERSION):void {
   if (versionCheck != VERSION) {
       throw new Error ("The version check failed! This library is version " + VERSION + ". Update your code or GTFO!");
   }
   // initialize library here
}

And when you run the initializer, use the version number you’re expecting.

MyLibrary.initialize("1.6");

Some things to notice with this approach:

  • I used a string instead of a number for the version number so that it would allow for sub-sub version numbers and other markers, e.g. “1.6.24 beta r545″
  • Because there is a default value for versionCheck in the initializer, providing a version number is optional. Using MyLibrary.initialize() will still work and throw no errors.
  • Unfortunately, there is not much you can do if the version numbers don’t match except to warn the client that the external code has changed. Still, I’ve found this to be very useful.

The code for my initializer in its entirety after the jump…
Continue reading

Tagged , , ,