AS3 – Which button is pressed?

OK this is a simple one, yet quite handy trick.

Problem

You need to show to the user which button is pressed – but also, if the user presses another button of your buttons-group to “unpress” the previous one.

Here’s what we are trying to do:

[swfobj src=”http://0x109.tuxfamily.org/wp-content/uploads/2011/12/buttons_full_functioning.swf” width=”150″ height=”200″]

Analysis

Yeah, I know what you’d say, to use a variable to store the id (name, or any characteristic attribute) of the pressed button, then refer to the value of that variable to trigger a “reset” process. Well, not for me: if I can avoid a variable, I do it. It is just a habit developed through years of struggling with tons of variables- I got sick of it! So, here’s a simple interaction design I came up with, after all those years:

  1. The pressed button informs every other button that belongs in its buttons-set to reset.
  2. The pressed button marks itself as “pressed”.

Simple and effective. The only problem is, actually, how can the button decide which of the other movie clips that reside in the same DisplayObjectContainer can actually respond to a doReset() command. Because, if those movieClips or sprites do not include a doReset() function, most likely the AS3 debugger wont let you to compile your project. So, here’s my solution:

  1. The pressed button loops through all of it’s siblings.
  2. For each one of them, it checks if they are instances of the same class.
  3. If the certain instance, at each step of the loop is an instance of the same class with the pressed button, our button issues a doReset() command to it (obviously it also does it to itself, but that’s not a problem).
  4. When the loop is finished, our button changes its own appearance, so that it looks “pressed” (or “selected” for that matter).

Before we start coding…

Now, let’s get on building it. Create a graphic the size and color you want your button to be, select it and press F8 to convert it to symbol. Name it “myButton” and press OK. Now, open “myButton” (double click on its icon in your Library), add a new layer and name it “texter”. Create a dynamic textField, remember to embed the font you prefer, and name it “theLabel”. Remember to change the color of the text of field to something different than the color of the underlying graphic. Place the textField over your graphic.

We are not over yet. We’re gonna change the color of our button when pressed, on rolled over, on rollout and  on click. But this poses a problem: if we change the color of the button as a whole, it will also change the color of the textField, and therefore the button label will become unreadable. Bummer – or is it? Hm… While into “myButton”, select the graphic, hit F8, name it “inner” and press OK. Yes, now you got a movieClip, within a movieClip. Click on the instance of “inner”, and name it “inner” in the properties inspector. Now, we can change the color of “inner” and let the rest of our button unchanged. Finnally, create one more layer and name it “actions”. Click on the first frame of “actions” and hit F9 to open the actions window – its tab should read “Actions – Frame”. If not, review what you did!

On to coding

First, let’s store a reference to the parent of our instances:

var myParent:MovieClip=MovieClip(this.parent);

Now, since we intent to use it as a button, the cursor should change to pointer over it. Furthermore, since we put into it a textField, the latter should not interfere with the looks of our cursor. So:

//Look like a button, change the cursor
this.buttonMode=true;
//The textField won't affect the cursor
this.mouseChildren=false;

 

At this point we consider parameterizing the label of the button. That is, we want each instance to have a different label. So, we will add an “abstract” reference to the text that should be put in the “theLabel” textField, and also issue a command to fill the textField with that text:

//---------------------------------------------------
//This is parameterized
var myText:String;
myLabel.text=myText;
//---------------------------------------------------

Now, let’s start adding interactivity.

this.addEventListener(MouseEvent.ROLL_OVER, onOver);

function onOver (evt:MouseEvent):void {
    var newColor:ColorTransform=new ColorTransform();
    newColor.color=0xFF9900;
    inner.transform.colorTransform=newColor;
}
//---------------------------------------------------
this.addEventListener(MouseEvent.ROLL_OUT, onOut);

function onOut (evt:MouseEvent):void {
    var newColor:ColorTransform=new ColorTransform();
    inner.transform.colorTransform=newColor;
}
//---------------------------------------------------

OK, now the CLICK event that does the trick sought:

//---------------------------------------------------
this.addEventListener(MouseEvent.CLICK, onClick);

function onClick (evt:MouseEvent):void {
	commandMySiblings();
	iAmPressed();
}
//---------------------------------------------------

A-ha what do commandMySiblings() and iAmPressed() stand for? Obviously two functions – what else? Here they are, with some more functions that complete the trick:

//---------------------------------------------------
this.addEventListener(MouseEvent.CLICK, onClick);

function onClick (evt:MouseEvent):void {
	commandMySiblings();
	iAmPressed();
}
//---------------------------------------------------
//A function that returns the name of the class
//an object is created from as a string. Kudos to
//-->http://delfeld.wordpress.com/2009/04/21/object_from_class_name/
function getClassName(obj:Object):String {
	return String(getDefinitionByName(getQualifiedClassName(obj)));
}
//---------------------------------------------------
//A function that checks every simbling of this object
//to see if they're offsprings of the same class. If they
//are, it issues a doReset command to it
function commandMySiblings():void {
	for (var i:uint=0; i < myParent.numChildren; i++) {
		var theClip=myParent.getChildAt(i);
		if (getClassName(theClip) == getClassName(this)) {
				theClip.doReset();
		}
	}
}
//----------------------------------------------------
//A function that actually reverses what iAmPressed does,
//i.e. brings the button back to its original state
function doReset():void {
	var newColor:ColorTransform=new ColorTransform();
	inner.transform.colorTransform=newColor;
	this.addEventListener(MouseEvent.ROLL_OUT, onOut);
	this.addEventListener(MouseEvent.ROLL_OVER, onOver);
}
//----------------------------------------------------
//A function that changes the color of the button to
//indicate it selected, and removes the event handlers
//so that it will ot change its appearance any more
//(until it is reset).

function iAmPressed():void {
	var newColor:ColorTransform=new ColorTransform();
	newColor.color=0x336699;
	inner.transform.colorTransform=newColor;
	this.removeEventListener(MouseEvent.ROLL_OUT, onOut);
	this.removeEventListener(MouseEvent.ROLL_OVER, onOver);
}
//----------------------------------------------------

 Oops!

We’re not done yet – one last step. Go to the Library, select “myButton”, and right-click on it. Select “Component definition”. At the window that opens, press “+”. In the field “Name”, type “The label of the button”, at the field “Variable”, type “myText” and at the field “Type”, select “String”. Now, get out of the “myButton” class, i.e. select “Scene 1” at the main window. Click on the button instance, select parameters (or component parameters), and type the label you want your button to have. Drag as many instances you like, from the Library onto the stage and do the same.

Finally, run your file and check it out.

 Code

Here’s all the code:

var myParent:MovieClip=MovieClip(this.parent);
//Look like a button, change the cursor
this.buttonMode=true;
//The textField wont affect the cursor
this.mouseChildren=false;
//---------------------------------------------------
//This is parameterized
var myText:String;
myLabel.text=myText;

//---------------------------------------------------
this.addEventListener(MouseEvent.ROLL_OVER, onOver);

function onOver (evt:MouseEvent):void {
	var newColor:ColorTransform=new ColorTransform();
	newColor.color=0xFF9900;
	inner.transform.colorTransform=newColor;
}
//---------------------------------------------------
this.addEventListener(MouseEvent.ROLL_OUT, onOut);

function onOut (evt:MouseEvent):void {
	var newColor:ColorTransform=new ColorTransform();
	inner.transform.colorTransform=newColor;
}
//---------------------------------------------------
this.addEventListener(MouseEvent.CLICK, onClick);

function onClick (evt:MouseEvent):void {
	commandMySiblings();
	iAmPressed();
}
//---------------------------------------------------
//A function that returns the name of the class
//an object is created from as a string. Kudos to
//-->http://delfeld.wordpress.com/2009/04/21/object_from_class_name/
function getClassName(obj:Object):String {
	return String(getDefinitionByName(getQualifiedClassName(obj)));
}
//---------------------------------------------------
//A function that checks every simbling of this object
//to see if they're offsprings of the same class. If they
//are, it issues a doReset command to it
function commandMySiblings():void {
	for (var i:uint=0; i < myParent.numChildren; i++) {
		var theClip=myParent.getChildAt(i);
		if (getClassName(theClip) == getClassName(this)) {
				theClip.doReset();
		}
	}
}
//----------------------------------------------------
//A function that actually reverses what iAmPressed does,
//i.e. brings the button back to its original state
function doReset():void {
	var newColor:ColorTransform=new ColorTransform();
	inner.transform.colorTransform=newColor;
	this.addEventListener(MouseEvent.ROLL_OUT, onOut);
	this.addEventListener(MouseEvent.ROLL_OVER, onOver);
}
//----------------------------------------------------
//A function that changes the color of the button to
//indicate it selected, and removes the event handlers
//so that it will ot change its appearance any more
//(until it is reset).

function iAmPressed():void {
	var newColor:ColorTransform=new ColorTransform();
	newColor.color=0x336699;
	inner.transform.colorTransform=newColor;
	this.removeEventListener(MouseEvent.ROLL_OUT, onOut);
	this.removeEventListener(MouseEvent.ROLL_OVER, onOver);
}
//----------------------------------------------------

Downloads

And here’s the file!

Acknowledgements

http://delfeld.wordpress.com/2009/04/21/object_from_class_name/

See also

The same trick in jQuery

One response to “AS3 – Which button is pressed?

  1. Pingback: jQuery – Which button is pressed? | 0×109

Leave a Reply

Your email address will not be published. Required fields are marked *