Categories
Articles

AIR Flex Custom Events in a Component

A common error in creating custom events inside of a component is the dispatching of the event using the event type you have created in the the custom event.

In an application you may be dealing with events that are solely called from Actionscript and have no UI and event that are part of a UI.

In the case of events that have a UI you may create a component the UI and want to show the event in the code help and as part of the MXML tag. This is where your thinking can get crossed where you think in terms of event types in Actionscript only events.

Consider this custom event.

package com.who.events
{
	import flash.events.Event;
	
	public class MyCustomEvent extends Event
	{
		public static const STOP:String = "com.who.events.MyCustomEvent.stop";
		public function MyCustomEvent(type:String = STOP, bubbles:Boolean=false, cancelable:Boolean=false) 
		{
			super(type, bubbles, cancelable);
			
			
		}
		override public function clone():Event 
		{
			return new MyCustomEvent(type, bubbles, cancelable);
		}
	}
}

The event type is a package path name giving it a unique name.

To dispatch the event you might use this:

 
...
var myCustomEvent:MyCustomEvent= new MyCustomEvent(MyCustomEvent.STOP);
dispatchEvent(mainViewCallEvent);
...

This is the same as

	
...	
var myCustomEvent:MyCustomEvent= new MyCustomEvent("com.who.events.MyCustomEvent.stop");
dispatchEvent(mainViewCallEvent);
...

The code for listening to the event would be

	
...			
componentId.addEventListener(MyCustomEvent.STOP, eventHandlerMethodName,true,0,true);
...

Now you want include the event so it is part of the MXML of a component:

...
	<fx:Metadata>
		[Event(name="stop", type="com.who.events.MyCustomEvent")] 
		
	</fx:Metadata>
...

The name can be anything you want but the inclination is to use the name appended to the end of the type in the custom event class. In this case stop. However the event will not longer be seen. The fix is to change the creation of the event instance for dispatching.

...		
var myCustomEvent:MyCustomEvent= new MyCustomEvent("stop");
dispatchEvent(mainViewCallEvent);
...
Categories
Articles

Actionscript 3.0 Debug Console Lite

By Lon (Alonzo) Hosford

I created this debug console for use in learning and teaching Actionscript programming. This is developed in pure Actionscript without component libraries. For that reason it can be used in Flash, AIR, and Flex. It will work in Flash IDE like Flash CS4 or Flex Builder. It also works creating Flash, Flex or AIR from the Flex SDK command line.

[ad name=”Google Adsense”]

The debug console plays in the published movie. It also outputs the results to the consoles in the respective IDEs: Flex Builder, Flash CS4, etc. You can turn that feature off and make the DebugConsole invisible when you publish if you wish.

This is an ActionScript project created in Flex Builder and updated to Flex Builder 4. Download the example code. You can build this with the free Flex SDK by using the code in the src folder. Same for Flash CS3 and CS4. You need to create a Flash Document in the src folder and set the document class to DebuggerLite.

If you want to use the DebugConsole in a Flash CS4 or CS3 you do not need to set the document class to DebuggerLite. Rather in Actionscript you include this code:

import com.lonhosford.util.debug.lite.DebugConsole
var debugConsole:DebugConsole = DebugConsole.getInstance();
stage.addChild(debugConsole);
debugConsole.width = 200;
debugConsole.height = 200;
debugConsole.write("Hello World");

For your convenience you can download a Flash CS4 ready to go example.

Testing Application In Flex Builder
This is a testing Actionscript application in Flex Builder. No Flash or Flex components are used so there is not need to import libraries. The DebugConsole class is instantiated as _debugConsole on line 23. It is a singleton design pattern so only one exists for the application.

A Timer is used to generate entries to the DebugConsole. The Timer is instantiated on line 24 as _testTimer.

The _testTimeCount variable is used to determine how many generated entries to the DebugConsole. General purpose is to see when vertical scroll bar appears.

The _showWideLineAt variable on line 25 is used add a very wide line of text to trip showing the horizontal scroll bar. The _showWideLineAt variable trips this when it equal _testTimer.currentCount value.

The _testTimeDelay variable on line 26 is the millisecond value for the _testTimer. Just depends on how fast you want to see the automated updates to the DebugConsole.

/**
 *  Purpose: Test Debugger Lite
	<p>Author: Lon Hosford www.lonhosford.com 908 996 3773</p>
	<p>Date: March 12, 2010</p>
 * */
package
{
	import com.lonhosford.util.debug.lite.DebugConsole;
	
	import flash.display.Sprite;
	import flash.events.KeyboardEvent;
	import flash.events.TimerEvent;
	import flash.ui.Keyboard;
	import flash.utils.Timer;
	
	[SWF(width=500, height = 300, frameRate = 30)]
	/**
	 * Testing application for DebugConsole.
	 * @see com.lonhosford.util.debug.lite.DebugConsole  
	 * */
	public class DebuggerLite extends Sprite
	{
		private var _debugConsole:DebugConsole = DebugConsole.getInstance();
		private var _testTimeCount:Number = 15; 
		private var _showWideLineAt:Number = 2; 
		private var _testTimeDelay:Number = 250; 
		private var _testTimer:Timer; 
		public function DebuggerLite()
		{
			stage.addChild(_debugConsole);
			_debugConsole.width = stage.stageWidth;
			_debugConsole.height = stage.stageHeight;
			
			_testTimer = new Timer(_testTimeDelay,_testTimeCount); 
			_testTimer.addEventListener(TimerEvent.TIMER,testTimerEventHandler);
			_testTimer.addEventListener(TimerEvent.TIMER_COMPLETE,testTimerCompleteEventHandler);
			stage.addEventListener(KeyboardEvent.KEY_UP, stageKeyUpEventHandler);
			start();
		
		}
		/**
		 * Starts the automated testing.
		 * */
		private function start():void
		{
		_debugConsole.write("Debugger Lite Tester");
		_debugConsole.write("Hit Space Bar to Clear.");
		_debugConsole.write("Hit Ctr+ Space Bar to Repeat.");
		_debugConsole.write("\n");
		_testTimer.start();
			
		}
		/**
		 * Handles the KeyboardEvent.KEY_UP event for the stage.
		 * */
		private function stageKeyUpEventHandler(event:KeyboardEvent):void 
		{
			// Space bar
			if ( event.keyCode == Keyboard.SPACE )
			{
				// Control key
				if (event.ctrlKey)
				{
					_testTimer.stop();
					_testTimer.reset();
					_debugConsole.clear();
					start();
				}
				// No control key
				else
				{
					_debugConsole.clear();
				}
				
			}
		}
		/**
		 * Handles the TimerEvent.TIMER event.
		 * */
		private function testTimerEventHandler(event:TimerEvent):void 
		{
			_debugConsole.write(new Date().toTimeString());
			if (_testTimer.currentCount == _showWideLineAt)
			{
				_debugConsole.write("START Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. END");
				
			}
		}
		/**
		 * Handles the TimerEvent.TIMER_COMPLETE event.
		 * */
		private function testTimerCompleteEventHandler(event:TimerEvent):void 
		{
			_debugConsole.write("LAST LINE");
		}
	}
}

[ad name=”Google Adsense”]
DebugConsole Class
This is the DebugConsole class. It is a singleton and as such can be instantiated anywhere in your code to use the write() method on line 291. The DebugConsole write() method calls the Debugger class write()method. The Debugger class write()method dispatches a DebuggerEvent.WRITE which the DebugConsole listens in the consoleUpdate() on line 308. For this reason you can also instantiate the Debugger class in code and use its write() method if you prefer. You only need to instantiate the DebugConsole where you intend to add it to your display.

package com.lonhosford.util.debug.lite
{
	import flash.display.Sprite;
	import flash.events.Event;
	import flash.events.MouseEvent;
	import flash.text.TextField;
	import flash.text.TextFieldAutoSize;
	import flash.text.TextFormat;
	import flash.text.TextFormatAlign;
	
	/**
	 *  UI for debug.lite package
	 * */
	public class DebugConsole extends Sprite
	{
		private static var _instance:DebugConsole;					// Singleton instance
		private var _debugger:Debugger;								
		private var _content_tf:TextField;							// The console content
		private var _lineCount_tf:TextField;						// The line count					
		private var _width:Number = 0;								// Width
		private var _height:Number = 0;								// Height
		private var _scrollVContainer:Sprite;						// Vertical scroller container
		private var _scrollHContainer:Sprite;						// Horizontal scroller container
		private var _scrollLeftButton:DebugConsoleArrowButton;		// Scroll left button
		private var _scrollRightButton:DebugConsoleArrowButton;		// Scroll right button
		private var _scrollUpButton:DebugConsoleArrowButton;		// Scroll up button
		private var _scrollDownButton:DebugConsoleArrowButton;		// Scroll down button
		private var _horizontalScrollIncrement:int = 10;			// Character count increment for horizontal scrolling
		private var _verticalScrollIncrement:int = 1;				// Line count increment for vertical scrolling.
		private var _autoScroll:Boolean = true;						// Autoscroll to last line
		
		/**
		 *  Constructor
		 * 
		 * @param pvt Enforces a singleton pattern.
		 * @see #getInstance() 
		 * */
		public function DebugConsole(pvt:DebugConsolePrivateClass)
		{
			_content_tf = new TextField();
			_lineCount_tf = new TextField();
			
			var format:TextFormat = new TextFormat();
			format.font = "_typewriter";
			format.color = 0x000000;
			format.size = 12;
			format.indent = 2;
			_content_tf.defaultTextFormat = format;
			_content_tf.background= true;
			_content_tf.backgroundColor = 0xffffff;
			
			var format2:TextFormat = new TextFormat();
			format2.font = "_typewriter";
			format2.color = 0x000000;
			format2.size = 12;
			format2.leftMargin = 1
			format2.align = TextFormatAlign.RIGHT;
			//format2.indent = 1;
			
			_lineCount_tf.defaultTextFormat = format2;
			_lineCount_tf.background= true;
			_lineCount_tf.backgroundColor = 0xcccccc;
	
			_content_tf.addEventListener(Event.SCROLL, _console_tfScrollHandler);

			_scrollHContainer = new Sprite();
			_scrollVContainer = new Sprite();
			
			_scrollLeftButton = new DebugConsoleArrowButton();
			_scrollLeftButton.addEventListener(MouseEvent.CLICK,scrollLeftButtonMouseClick);
			_scrollRightButton = new DebugConsoleArrowButton();
			_scrollRightButton.addEventListener(MouseEvent.CLICK,scrollRightButtonMouseClick);
			
			_scrollUpButton = new DebugConsoleArrowButton();
			_scrollUpButton.addEventListener(MouseEvent.CLICK,scrollUpButtonMouseClick);
			_scrollDownButton = new DebugConsoleArrowButton();
			_scrollDownButton.addEventListener(MouseEvent.CLICK,scrollDownButtonMouseClick);
			
			addChild(_content_tf);
			addChild(_lineCount_tf);
			addChild(_scrollHContainer);
			addChild(_scrollVContainer);
			_scrollHContainer.addChild(_scrollLeftButton);
			_scrollHContainer.addChild(_scrollRightButton);
			_scrollVContainer.addChild(_scrollUpButton);
			_scrollVContainer.addChild(_scrollDownButton);
			_debugger = Debugger.getInstance();
			_debugger.addEventListener(DebuggerEvent.WRITE,consoleUpdate);
			
		}
		/**
		 * Singleton instantiation method
		 * */
		public static function getInstance():DebugConsole
		{
			if (DebugConsole._instance == null)
			{
				DebugConsole._instance = new DebugConsole(new DebugConsolePrivateClass());
			}
			return DebugConsole._instance;
		}
		/**
		 * Redraws the components
		 * */
		private function draw():void
		{
			var rightPanelHeight:Number;
			var bottomPanelWidth:Number;
			var lineCount_tf_width:Number = _lineCount_tf.textWidth + 12;// Extra for TextField overhead
			var bottomPanelHeight:Number = 20;
			var rightPanelWidth:Number = 20;
				
			var tfHeight:Number;// = _height;
			var tfWidth:Number = _width;
			// Component border
			graphics.clear();
			graphics.beginFill(0xffffff);
			graphics.lineStyle(2, 0x000000);
			graphics.drawRect(0, 0, _width, _height);
			graphics.endFill();
			_scrollLeftButton.draw(
				bottomPanelHeight,
				bottomPanelHeight,
				0x00ffff,
				1,
				0x000000,
				0x666666,
				90
			);
			_scrollRightButton.draw(
				bottomPanelHeight,
				bottomPanelHeight,
				0x00ffff,
				1,
				0x000000,
				0x666666,
				-90
			);
			
			_scrollUpButton.draw(
				rightPanelWidth,
				rightPanelWidth,
				0x00ffff,
				1,
				0x000000,
				0x666666,
				0
			);
			_scrollDownButton.draw(
				rightPanelWidth,
				rightPanelWidth,
				0x00ffff,
				1,
				0x000000,
				0x666666,
				180
			);
			tfHeight = height
			rightPanelHeight = height-3;
			bottomPanelWidth = width - 3 - lineCount_tf_width;
			if (_content_tf.textHeight > _content_tf.height)
			{
				bottomPanelWidth -= rightPanelWidth - 1;
			}
			if (_content_tf.textWidth > _content_tf.width)
			{
				rightPanelHeight -= bottomPanelHeight - 1;
			}
			// Right scrollbar panel
			if (_content_tf.textHeight > _content_tf.height)
			{
				_scrollUpButton.x = 0;
				_scrollUpButton.y = 0;
				_scrollDownButton.x = 0;
				_scrollDownButton.y = 0;
				_scrollVContainer.graphics.clear();
				
				_scrollVContainer.graphics.beginFill(0xcccccc);
				_scrollVContainer.graphics.lineStyle(1, 0x000000);
				_scrollVContainer.graphics.drawRect(0, 0, rightPanelWidth - 1, rightPanelHeight);
				_scrollVContainer.graphics.endFill();
				_scrollVContainer.x = _width - _scrollVContainer.width + .5;
				_scrollVContainer.y = .5;

				
				_scrollDownButton.x = (_scrollVContainer.width - _scrollDownButton.width) ;
				_scrollDownButton.y = (_scrollVContainer.height - _scrollDownButton.height) ;
				_scrollUpButton.x = _scrollDownButton.x;
				_scrollUpButton.y = 0;
				
				tfWidth -= _scrollVContainer.width - 1;
				
				_scrollVContainer.visible = true;
			}
			else
			{
				_scrollVContainer.visible = false;
			}
			// Bottom scrollbar panel
			if (_content_tf.textWidth > _content_tf.width)
			{
				_scrollLeftButton.x = 0;
				_scrollLeftButton.y = 0;
				_scrollRightButton.x = 0;
				_scrollRightButton.y = 0;
				_scrollHContainer.graphics.clear();
				_scrollHContainer.graphics.beginFill(0xcccccc);
				_scrollHContainer.graphics.lineStyle(1, 0x000000);
				_scrollHContainer.graphics.drawRect(0, 0, bottomPanelWidth, bottomPanelHeight - 1);
				_scrollHContainer.graphics.endFill();
				_scrollHContainer.y = _height - _scrollHContainer.height + .5;
				_scrollHContainer.x = lineCount_tf_width;
				_scrollLeftButton.x = (_scrollHContainer.width - _scrollLeftButton.width) ;
				_scrollLeftButton.y = (_scrollHContainer.height - _scrollLeftButton.height) ;
				_scrollRightButton.x = 0;
				_scrollRightButton.y = _scrollLeftButton.y;

				_scrollHContainer.visible = true;
				tfHeight -= _scrollHContainer.height -1;
			}
			else
			{
				_scrollHContainer.visible = false;
			}
			
			// Left bottom rectangle if horizontal and vertical scroll bars are visible.
			if (_scrollHContainer.visible && _scrollVContainer.visible)
			{
				graphics.beginFill(0xcccccc);
				graphics.lineStyle(0, 0x000000,0);
				graphics.drawRect(_scrollHContainer.x + _scrollHContainer.width, _scrollVContainer.height, bottomPanelHeight-2, bottomPanelHeight-2);
				graphics.endFill();
			}
			// Left bottom rectangle if horizontal scroll bar is visible.
			if (_scrollHContainer.visible)
			{
				graphics.beginFill(0xcccccc);
				graphics.lineStyle(1, 0x000000,100);
				graphics.drawRect( 0, _scrollHContainer.y, lineCount_tf_width, bottomPanelHeight-1);
				graphics.endFill();
			}
			
			// Position and resize line count text field.
			_lineCount_tf.width = lineCount_tf_width;	
			_lineCount_tf.height = tfHeight - 4;			
			_lineCount_tf.x = 1;
			_lineCount_tf.y = 1;
			
			_lineCount_tf.scrollV = _content_tf.scrollV;
			
			// Position and resize line content text field.
			_content_tf.width = tfWidth - 2 - lineCount_tf_width;
			_content_tf.height = _lineCount_tf.height;
			_content_tf.x = _lineCount_tf.x + _lineCount_tf.width ;
			_content_tf.y = _lineCount_tf.y;
			
			_scrollUpButton.enabled =  _content_tf.scrollV != 1;
			_scrollDownButton.enabled =  _content_tf.scrollV != _content_tf.maxScrollV;
			_scrollLeftButton.enabled =  _content_tf.scrollH != _content_tf.maxScrollH;
			_scrollRightButton.enabled =  _content_tf.scrollH != 0;
		}
		/**
		 * Change width
		 * */
		override public function set width(width:Number):void
		{
			_width = width;
			draw();
		}
		/**
		 * Change height
		 * */
		override public function set height(height:Number):void
		{
			_height = height;
			draw();
			
		}
		/**
		 * Scroll to last line. 
		 * @default true  
		 * */
		public function set autoScroll(autoScrollEnabled:Boolean):void
		{
			_autoScroll = autoScrollEnabled;
		}
		/**
		 * Adds one line. Multiple lines can be added inserting \n. A blank line can be added with \n.
		 * <p>The writing is delegated to the Debugger class.</p>
		 * @see com.lonhosford.util.debug.lite.Debugger.write()
		 * */
		public function write(msg:String):void 
		{
			_debugger.write(msg);
		}
		/**
		 * Clears the display. Line count is not reset to 0 and continues to increment.
		 * */
		public function clear():void 
		{
			_lineCount_tf.text = "";
			_content_tf.text = "";
			draw();
		}
		/**
		 * Handles the DebuggerEvent.WRITE event.
		 * */
		private function consoleUpdate(e:DebuggerEvent):void
		{
			var debugMessage:DebugMessage = e.debugMessage;
			
			_lineCount_tf.appendText(debugMessage.lineNumber + "." + "\n");
			if (debugMessage.text == "\n")
			{
				debugMessage.text = "";
			}
			_content_tf.appendText( debugMessage.text + "\n");
			if(_autoScroll)
			{
				_content_tf.scrollV = _content_tf.maxScrollV;
			}			
			draw();
		}
		/**
		 * Handler for the scrollUpButton MouseEvent.CLICK event.
		 * */

		private function scrollUpButtonMouseClick(e:MouseEvent):void
		{
			if (_content_tf.scrollV <= _verticalScrollIncrement)
			{
				_content_tf.scrollV = 1;
			}
			else
			{
				_content_tf.scrollV -= _verticalScrollIncrement;
			}
			draw();
		}
		/**
		 * Handler for the scrollRightButton MouseEvent.CLICK event.
		 * */
		private function scrollRightButtonMouseClick(e:MouseEvent):void
		{
			if (_content_tf.scrollH <= _horizontalScrollIncrement)
			{
				_content_tf.scrollH = 0;
			}
			else
			{
				_content_tf.scrollH -= _horizontalScrollIncrement;
			}
			draw();
		}
		/**
		 * Handler for the scrollDownButton MouseEvent.CLICK event.
		 * */
		private function scrollDownButtonMouseClick(e:MouseEvent):void
		{
			
			if (_content_tf.scrollV + _verticalScrollIncrement >= _content_tf.maxScrollV)
			{
				_content_tf.scrollV = _content_tf.maxScrollV;
				
			}
			else
			{
				_content_tf.scrollV += _verticalScrollIncrement;
			}
			draw();
		}
		/**
		 * Handler for the scrollLeftButton MouseEvent.CLICK event.
		 * */
		private function scrollLeftButtonMouseClick(e:MouseEvent):void
		{
			
			if (_content_tf.scrollH + _horizontalScrollIncrement >= _content_tf.maxScrollH)
			{
				_content_tf.scrollH =_content_tf.maxScrollH;
				
			}
			else
			{
				_content_tf.scrollH += _horizontalScrollIncrement;
			}
			draw();
		}
		/**
		 * Handler for the _content_tf Event.SCROLL event.
		 * */
		public function _console_tfScrollHandler(event:Event):void
		{
			draw();
		}
	}
}
/**
 * Singleton enforcer class
 * */
class DebugConsolePrivateClass
{
	public function DebugConsolePrivateClass()
	{
		
	}
}

Debugger Class
This class receives write messages and dispatches them. It also will write to the IDE debug console on line 60.

package com.lonhosford.util.debug.lite
{
	import flash.events.EventDispatcher;
	/**
	 * Singleton for receiving and dispatching debugging messages
	 * */
	public class Debugger extends EventDispatcher
	{
		private static var _instance:Debugger;
		private var _msg:String;
		private var _isTracing:Boolean = true;		// State of using the trace() function.
		private var _lineCount:Number = 0;			// Line count of tracing messages
		private var _lang_productName:String = "Actionscript 3 Debugger Lite";
		private var _lang_productVersion:String = "Version";
		/**
		 *  Constructor
		 * 
		 * @param pvt Enforces a singleton pattern.
		 * @see #getInstance() 
		 * */
		public function Debugger(pvt:DebuggerPrivateClass)
		{
		}
		/**
		 * Singleton instantiation method
		 * */
		public static function getInstance():Debugger
		{
			if (Debugger._instance == null)
			{
				Debugger._instance = new Debugger(new DebuggerPrivateClass());
			}
			return Debugger._instance;
		}
		/**
		 * Turns on or off tracing to the Flash or Flex IDE console.
		 * @default true
		 * */
		public function set isTracing(value:Boolean):void
		{
			_isTracing = value;
		}
		/**
		 * Adds one line. Multiple lines can be added inserting \n. A blank line can be added with \n.		 * <p>The writing is delegated to the Debugger class.</p>
		 * */
		public function write(msg:String):void 
		{
			var messageLines:Array = new Array();
			if (msg == "\n") 
			{
				messageLines.push("");
			}
			else
			{
				messageLines = msg.split("\n")
			}
			
			
			if (_isTracing)
			{
				trace(msg);
			}
			if ( _lineCount == 0 )
			{
				messageLines.splice(0,0,_lang_productName + "\t" + _lang_productVersion + " " + DebugVersion.VERSION);
				messageLines.splice(1,0, DebugVersion.AUTHOR + "\t" + DebugVersion.AUTHOR_WEB_SITE);
				messageLines.splice(2,0,"\n");
			}
			for (var msgLinesIndex:uint = 0; msgLinesIndex <= messageLines.length - 1; msgLinesIndex++)
			{
				dispatchMessageEvent(messageLines[msgLinesIndex]);
			}
		}
		/**
		 * Dispatches a DebuggerEvent.WRITE
		 * @see DebuggerEvent
		 * @see DebugMessage
		 * */
		private function dispatchMessageEvent(msg:String):void
		{
			var debugMessage:DebugMessage = new DebugMessage();
			debugMessage.text = msg;
			debugMessage.lineNumber = ++_lineCount;
			var e:DebuggerEvent = new DebuggerEvent(DebuggerEvent.WRITE,  debugMessage);
			dispatchEvent(e);
		}
	}
}
/**
 * Singleton enforcer class
 * */
class DebuggerPrivateClass
{
	public function DebuggerPrivateClass()
	{
		
	}
}

[ad name=”Google Adsense”]
DebugConsoleArrowButton Class
UI for the scroll buttons. Simple shapes using a triangle to indicate direction of scroll.

package com.lonhosford.util.debug.lite
{
	import flash.display.Sprite;
	import flash.events.MouseEvent;
	import flash.events.TimerEvent;
	import flash.utils.Timer;
	/**
	 * Arrow button UI and logic
	 * */
	public class DebugConsoleArrowButton extends Sprite
	{
		private var _container:Sprite = new Sprite();
		private var _triangle:DebugTriangleShape = new DebugTriangleShape();
		private var _backgroundRect:Sprite = new Sprite();
		private var _width:Number;
		private var _height:Number;
		private var _color:int;										// Color of arrow.
		private var _borderWidth:Number;							// Border width of button.
		private var _borderColor:int;								// Border color of button.
		private var _backgroundColor:int;							// Background color of button.
		private var _direction:Number;								// Rotation of the UI.
		private var _mouseDownStartTimeDelay:Number = 350; 			// Initial delay before starting repeating MouseEvent.CLICK events.
		private var _mouseDownTimeDelay:Number = 100; 				// Delay between each MouseEvent.CLICK event.
		private var _mouseDownTimer:Timer; 							// Timer for repeating MouseEvent.CLICK events.
		/**
		 * Constructor
		 * */
		public function DebugConsoleArrowButton()
		{
			_mouseDownTimer = new Timer(_mouseDownTimeDelay,0); 
			_mouseDownTimer.addEventListener(TimerEvent.TIMER,mouseDownTimerEventHandler);
			_container.addChild(_backgroundRect);			
			_backgroundRect.addChild(_triangle);
			addChild(_container);
		}
		/**
		 * Handler for TimerEvent.TIMER event. Resets the delay interval once the default delay 
		 * is reached.
		 * */
		private function mouseDownTimerEventHandler(event:TimerEvent):void 
		{
			if (_mouseDownTimer.delay == _mouseDownStartTimeDelay)
			{
				_mouseDownTimer.delay = _mouseDownTimeDelay;
			}
			
			var e:MouseEvent = new MouseEvent(MouseEvent.CLICK);
			dispatchEvent(e);
		}
		/**
		 * Sets enabled state.
		 * */
		internal function set enabled(enabledState:Boolean):void
		{
			alpha = enabledState ? 1 : .25;
			if (enabledState)
			{
				addEventListener(MouseEvent.MOUSE_UP,mouseUpEventHandler);
				addEventListener(MouseEvent.MOUSE_DOWN,mouseDownEventHandler);
				addEventListener(MouseEvent.MOUSE_OUT,mouseOutEventHandler);
			}		
		}
		/**
		 * Handler for MouseEvent.MOUSE_OUT event. Stops the mouse down repeat timer.
		 * */
		private function mouseOutEventHandler(e:MouseEvent):void
		{
			_mouseDownTimer.stop();		
		}
		/**
		 * Handler for MouseEvent.MOUSE_UP event. Stops the mouse down repeat timer.
		 * */
		private function mouseUpEventHandler(e:MouseEvent):void
		{
			_mouseDownTimer.stop();		
		}
		/**
		 * Handler for MouseEvent.MOUSE_DOWN event. Starts mouse down timer.
		 * */
		private function mouseDownEventHandler(e:MouseEvent):void
		{
			_mouseDownTimer.delay = _mouseDownStartTimeDelay;
			_mouseDownTimer.start();
		}
		/**
		 * Draw the button UI.
		 * */
		internal function draw(
			p_width:Number, 
			p_height:Number, 
			color:int,
			borderWidth:Number,
			borderColor:int,
			backgroundColor:int,
			direction:Number = 0):void
		{
			_width = p_width;
			_height = p_height;
			_color = color;
			_borderWidth = borderWidth;
			_borderColor = borderColor;
			_backgroundColor = backgroundColor;
			_direction = direction;
		
			_backgroundRect.graphics.clear();
			_backgroundRect.graphics.beginFill(_backgroundColor);
			_backgroundRect.graphics.lineStyle(_borderWidth, _borderColor); 
			_backgroundRect.graphics.drawRect(0, 0, _width - _borderWidth, _height - _borderWidth); 
			_backgroundRect.graphics.endFill();
			
			_triangle.draw( _width  , 0,_color, _color);
			_triangle.scaleX = _triangle.scaleY = .6;
			_triangle.x =  (_triangle.width / 2) + ((_width - _triangle.width - _borderWidth) / 2) ;
			_triangle.y =  (_triangle.height / 2) + ((_height - _triangle.height - _borderWidth) / 2);
			_triangle.rotation = _direction;
		}
	}
}

DebugTriangleShape Class
Utility to draw a rectangle shape with a center registration point.

package com.lonhosford.util.debug.lite
{
	import flash.display.Shape;
	import flash.display.Sprite;
	/**
	 * Utility to draw a triangle shape with a center registration point.
	 * */	
	public class DebugTriangleShape extends Sprite
	{
		
		public function DebugTriangleShape(
		)
		{
		}
		internal function draw(
			size:Number, 
			borderWidth:Number,
			borderColor:int,
			backgroundColor:int
				):void
		{
			graphics.clear();
			graphics.beginFill(backgroundColor);
			graphics.lineStyle(borderWidth, borderColor);
			size = size / 2;
			graphics.moveTo(-size, size);
			graphics.lineTo(-0, -size);  
			graphics.lineTo(size, size );
			
			graphics.endFill();
			
		}
	}
}

DebuggerEvent Class
Events for the Debugger class.

package com.lonhosford.util.debug.lite
{import flash.events.Event;
	/**
	 * Events for the Debugger
	 * @see DebugMessage
	 * @see Debugger
	 * */
	public class DebuggerEvent extends Event
	{
		public static const WRITE:String = "debug.DebuggerEvent.Write";
		public var debugMessage:DebugMessage;
		public function DebuggerEvent(type:String, debugMessage:DebugMessage)
		{
			super(type, bubbles);
			this.debugMessage = debugMessage
		}
		override public function clone():Event 
		{
			return new DebuggerEvent(type, debugMessage);
		}
	}
}

DebugMessage Class
The data values sent with the DebuggerEvent.

package com.lonhosford.util.debug.lite
{
	/**
	 * Data for a DebuggerEvent.
	 * @see DebuggerEvent
	 * */
	public class DebugMessage
	{
		public var text:String;
		public var lineNumber:Number;
		public function DebugMessage()
		{
		}
	}
}

DebugVersion Class
A place to hold the static values for the code.

package com.lonhosford.util.debug.lite
{
	/**
	 * Common version data.
	 * */	
	public final class DebugVersion 
	{
		public static const VERSION:String = "1.00.01";
		public static const AUTHOR:String = "Lon (Alonzo) Hosford";
		public static const AUTHOR_WEB_SITE:String = "https://www.lonhosford.com";
	}
}
Categories
Articles

Flex, Flash and Actionscript 3 Memory

I have been in on or called in on Flash and Flex applications that perform slowly.

When there is a back end, I recommend an isolation process to eliminate the move from the equation. This includes all data and dynamically loaded assets and movies.

When the backend is out of the way then the focus is on memory. This requires providing calls to memory information as the application is navigated. I provided basic shell code that works below you can consider for integration into a memory monitoring module for your application.

In designing Flash player movies whether you are using Flex or Flash should always side on caution in creating objects and loading assets. Its garbage collector works when it thinks it is ready. As well you need to care for the removal of event listeners when you remove objects.

The System class contains a property totalMemory. Here is an example so you can learn about it.

MemoryMonitor.as

package {

   import flash.events.TimerEvent;
   import flash.utils.Timer;
   import flash.system.System;

   public class MemoryMonitor
   {
      private var timer1:Timer = new Timer(1000, 0);
      private var timer2:Timer = new Timer(1000, 0);
      private var totalMemory:int;
      private var totalMemory_last:int = 0;

         public function MemoryMonitor():void
   {
         trace("MemoryMonitor()");
         timer1.addEventListener(TimerEvent.TIMER, _displayTotalMemory);
         timer2.addEventListener(TimerEvent.TIMER, _displayTotalMemoryOnChange);
      }

      public function displayTotalMemory():void
      {
         timer1.start();
      }
      public function displayTotalMemoryOnChange():void
      {
         timer2.start();
      }
      private function _displayTotalMemory(event:TimerEvent):void
      {
         trace("MemoryMonitor.displayTotalMemory() - System.totalMemory:\t\t" + totalAsMB(System.totalMemory) );
      }

      private function _displayTotalMemoryOnChange(event:TimerEvent):void
      {
         totalMemory = System.totalMemory;
         if (totalMemory != totalMemory_last)
         {
            trace("MemoryMonitor.displayTotalMemoryOnChange() - totalMemory_last:\t" + totalAsMB(totalMemory_last) );
            trace("MemoryMonitor.displayTotalMemoryOnChange() - System.totalMemory:" + totalAsMB(totalMemory) );
         }
         totalMemory_last = totalMemory;
      }
      private function totalAsMB(totalMemory:int):String
      {
         return (Math.round (((totalMemory / 1024)/1024) * 10)) / 10 + " MB"
      }
   }
}

Flash Movie frame 1 Actionscript

import MemoryMonitor;

var memoryMonitor:MemoryMonitor = new MemoryMonitor();

// Display memory every 1 second
memoryMonitor.displayTotalMemory();
// Display memory every 1 second if it changes
memoryMonitor.displayTotalMemoryOnChange();
Categories
Articles

FlashVars in Flash CS4

Publishing under Flash CS4 will provide the latest HTML wrapper with a boat load of Javascript. At one time a separate Javascript file was generated from the Flash IDE publishing. Now it is all in the HTML document.

The overall process is the same as it has been since first introduced. You need to publish the HTML one time and then turn it off as you need to edit the HTML document for your FlashVars. Dicing in the FlashVars for the new HTML wrapper appears as follows for the FlashVars variables message1 and name:

AC_FL_RunContent Javascript function arguments:

'movie', 'FlashVarsEx02','FlashVars', 'message1=Hello World&name=Alonzo (Lon) Hosford','salign', ''

Object tag for the no script possibility:

<param name="flashvars" value="message1=Hello World&name=Alonzo (Lon) Hosford" />

In Flash you extract the Flash vars as follows:

root.loaderInfo.parameters.name</p>
<pre><p>root.loaderInfo.parameters.message1</p>
<p>

An elegant way to dump all FlashVars

for (key in params)
{
	value = String(params[key]);
	trace ("\t" + key + "\t" + value );
}

Download completed FlashVars example for CS4 and Actionscript 3

Categories
Articles

Adobe Flex Localization Dynamically Loaded Resource Modules

I followed the example at  Adobe Labs written by Gordon Smith September 25, 2007 to create a basic language localization example that would load the locales dynamically at runtime.

I had some bumps in making the example work in that it did not load the language when launched. This could be due to differences in the  version Gordon was using or just those nasty timing issue you get in the Flex framework. The basic issue was to add an initialization event handler to the example and the line resourceManager.localeChain=[“en_US”]; in it.

However Gordon’s tutorial was essential to understanding the geekish implementation of Flex dynamic localization. You have the copylocale utility program to run in the Flex sdk bin folder to set up Flex for each language. I created a windows batch file for it and included in my example. It makes it easy to add a language to Flex at a later date with a simple copy and edit.

Flex uses a separate swf for each language to load them at run time. You create these with command line steps using the mxmlc compiler and lengthy arguments. Since you have to do this every time a language item changes, I again created some batch files to automate the process.

The completed example is located at Adobe Flex 3 Basic Locales Dynamic Runtime Localization With Resource Modules.

Categories
Articles

Adobe Flex 3 Runtime Language Localization Embedded Locals

I started to review the Adobe Flex 3 language localization. The site I used to learn is at Adobe Labs written by Gordon Smith September 25, 2007.

My opinion is the localization implementation suffers a geekish solution. So even Gordon’s super effort, you get lost in the terminology geeks have used to define the elements of localization features. So I did eventually get through to make my own examples based on Gordon’s work.

This example shows how to embed the locale language in the Flex swf. This of course make the Flex swf potentially larger. However if you have a small amount of language or only a few languages, you might find this solution more expedient.

Look it over and download at Adobe Flex 3 Basic Embedded Runtime Localization Locales.

I also followed Gordon’s modular version of localization. This allows loading localization data during runtime. Gordon’s example has problems with Flex timing when you go to put it to work. I solved the timing issues and will post on that as well with the fixes. But also there are even more geekish aspects to get Flex even set up to do this.

Categories
Articles

Adobe Flex Amazon Web Service Using Caringorm

[IMPORTANT AS OF AUGUST 1 2009 AMAZON CHANGED THE AUTHENTICATION PROCEDURES SO THIS EXAMPLE NO LONGER WORKS]

I am researching the Amazon Web Services API for use in Flex 3.

I reviewed the work of Jesse Warden at jessewarden.com and, I believe since the post is not signed, Charlie Key at paranoidferret.com.

Both were good starters. However they did not meet my needs exactly. But together they worked out to let me build an example in my own style.

My finished work can be found at Adobe Flex Amazon Web Services Music ItemSearch Using Cairngorm.

The example does a simple keyword search on Music using the Amazon ItemSearch API.

For the ancestors to this example see:

Jesse Warden: Flex Example: HTTPService & Cairngorm 2.2

Charlie Key: How to use Flex to get Music Info from Amazon Web Services

Categories
Articles

Adobe Flex VideoPlayer with Scrubber for Progressive Download and Flash Media Server Streaming

Frustrated finding a good basic Flex 3 video player using the VideoPlayer class and having a HSlider for the scrubber, I decided to make one myself.

I share it with you at Adobe Actionscript Flash Flex Examples.

I tested it with both progressive download and with Flash Media Server 3 at my hosting service Influxis.

It seems to run well. It does auto play each video.

The scrubber bar maintains the play or paused state. So if the video is paused, moving the scrubber bar when released does not start playing the video. Likewise if the video is playing, moving the scrubber bar continues play when the thumb is release.

I designed this not to resize the VideoDisplay when the Application is resized. This is because I wanted to use it for Camtasia screen captures. However adding width and height properties to 100%  to the VideoDisplay object resize the video playing.

Flex components used include VideoDisplay, DateFormatter,  Panel, ControlBar, ComboBox, HSlider,  Label, Button, VBox and HBox.

Enjoy!