Archive for the “experiments” Category

Hi Everyone,

This is not exactly a “Soma release”, but I would like to share with you my last work so we can talk about: A new AS3 MVC Framework with its own design philosophy.

Why another AS3 MVC Framework?

I’ve been working with different Frameworks in the last years, such as PureMVC, Cairngorm and Mate for the well-known. I’ve always knew that I would write my own “MVC design philosophy”, without taking big words, because I would have some needs that existing Frameworks wouldn’t completely fill.

That’s what happened. I needed a Flash lightweight framework, not DI, event based, working both for Flex or Pure AS3. The biggest inspirations have been PureMVC for the proxies and mediators, and Mate for their event system.

I’ll be starting an interesting AIR Modular app and I needed something that will easily allow me to have views and models free of Framework code, without creating tons of files or use any injection. I also wanted a Framework very flexible, so I can use it even for smaller project, being sure I’ll be effective in terms of development time.

Free the views and models

First problem, free the views and models of Framework code (loose-coupling). It seems there’s a wave of DI Framework but… I’ve never really been into DI Framework, because they tend to control the way you’re doing things. If you stick to it, it is fine, but I’ve always felt more freedom with framework like PureMVC. I might be wrong, it is just an opinion and not even entirely true as I didn’t felt that problem with Mate.

So, to solve this problem, I used the events Mate concept. A basic Flash Events that has a bubble property set to true can become Commands when they are mapped to a Command class. Those events can be intercepted, stopped and processed by the Framework (execute Commands). The great thing is, views and models are free of Framework code and can use Commands because they are just Flash native events.

Wires introduction

Second problem, was to “update” data or states in the views and models. PureMVC is using proxies and mediators and I like that approach. However, you end up by creating tons of files for the sake of loose-coupling pratice. So I’ve created something that I call “Wire”. Now software engineers or PureMVC adept might say that what I’m doing is wrong. I have no idea, I’m no computer scientist, I do what I feel and I’m sharing it with you.

Wire are classes that can contain Framework code and they will be the links between the models, the views, the Framework and… whatever you like. Wire can be proxies, they can be mediators, but they can also be both and handle more than one view or model.

Basically, they are as free as you want them to be. They can even be optional if you don’t care about good practice or loose-coupling programming. Wires have easy access to all the framework, models, commands and views. They can register create models, views, register commands or create other wires.

Update from comment:

So far I saw two ways to inject/update information into views without having framework code inside:

- Dependency Injection
- Buffer classes (such as Mediators and Proxies in PureMVC for the analogy, respectively for Views and Models). I mean “buffer” by classes that act as steward of other classes.

I’ve chosen the second way, and I’ve created a “buffer” class that I called a Wire.

Wires are completely free classes. I won’t tell you how to use them (because that’s up to you) but I can tell what you can do with them. Wires can be used to update views and models but they are not tight to anything. They are not even only tight to one tier. To create a wire class you extend Wire and implements IWire, and here are the roles they can take:

- a wire can act as steward of a view (such as Mediator in PureMVC)
- a wire can act as steward of a model (such as Proxies in PureMVC)
- a wire can manage both a view and a model
- a wire can manage multiple views and/or multiple models
- a wire can be considered as a subdivision of the framework and create its own views, create its own models and register its own commands. Much like you would create a specific package to hold a specific matter.

When I build something, I always try to keep a good level of freedom to handle problems how I like but most importantly, how they should be. If you like to have the framework telling you (or forcing you) how to build your application, fair enough but you won’t like it.

The wires are the free elements that will let you built your application the way you like or the way it is required to be. They can make your application rigid, segmented, flexible or centralized, depending of the role you are going to give them. They are so free that I believe remove (or lesser) what I call “Framework Fight”.

Let’s take an example, the Cafe TownSend below.

There are 2 wires: the LoginWire and the Employee Wire. They both register their own commands to control their views and models.

The Login Wire only handles a Login View.

The EmployeeWire handles 2 views: a list of employees and an employee details. But also 1 model (the employees data), all of them only related to employees matter.

SomaCore

I temporarily named this framework SomaCore and it has nothing to do with the Framework I released on this blog (Soma). However, this framework might become the core of what will be Soma v3.

I post this code hoping to get your feedback or point of view of what might be great or wrong in this framework.

Here is a diagram:

SomaCore MVC Diagram


Click here to download a zip file containing the Framework sources code (classes and SWC).

And here are some demos. I made a Flex Cafe TownSend demo and a pure AS3 demo.

SomaCore Flex Cafe TownSend SomaCore Flash AS3 Demo
View Demo
View Source
Download Source
View Demo
View Source
Download Source

This is a very early state, this Framework has not been used yet in a real project beside the demos above. Have a look and please comment what you feel is good or wrong in the core concept.

Romu

Vote in HexoSearch

Comments 10 Comments »

For a special purpose I had to extend a Singleton, to make my system fully flexible. I found complicated solutions that wasn't fully working as intended.

To use PureMVC, you have to extend a Singleton (Facade), which is the entry point of the framework. This is working only if you don't use the Facade class (the super Singleton) before using the subclass, otherwise you get an error, as the super singleton has already been instantiated.

Well this might be a simple solution but not working in my case.

First of all, they are a lot of solutions to correctly "lock" a Singleton, because in AS3, private constructor doesn't exist. Some of them have turn around, that you can solve with a bit more code, but the solution I prefer is instantiate the Singleton out of the constructor and method:

Actionscript:
  1. private static var _instance:Singleton = new Singleton();

So, if I use the super singleton with a Singleton.getInstance(), and then use the subclass with a SingletonExtended.getInstance(), this will throw an error as when the SingletonExtended is called, the Singleton is called as well and has already been instantiated.

The solution I found is compare the super class name with a static class name, basically you can't use the keyword "this" when you declare a variable, but using "super" will return the same result (well that's odd but it is what I saw):

Actionscript:
  1. private static var _className:String = getQualifiedClassName(super);

And then compare it with the super classname in the Singleton constructor:

Actionscript:
  1. if (_instance != null && getQualifiedSuperclassName(this) != _className) throw new Error

if I trace(_className + " - " + getQualifiedSuperclassName(this)) in the Singleton constructor:

- when I use the Singleton class, I get: "null - Object"
- when I use the SingletonExtended class, I get: "Singleton - Singleton", meaning the constructor has been called from a subclass.

Until now, it is working pretty well, I can use:

Actionscript:
  1. Singleton.getInstance().singletonValue
  2. SingletonExtended.getInstance().singletonValue
  3. SingletonExtended.getInstance().singletonExtendedValue

But we're not completely done. We can access to our two Singleton... but wait, "two Singleton", is that possible?

In fact, it is completely possible and it is even a problem. Let's say I have a undefined value in Singleton, like:

Actionscript:
  1. private var _myValueNotInitialized:String;

And then you have a public method that is setting a value to this variable:

Actionscript:
  1. public function initializeMyValue():void {
  2.     _myValueNotInitialized = "I am initialized";
  3. }

You can now use:

Actionscript:
  1. Singleton.getInstance().initializeMyValue();
  2. or
  3. SingletonExtended.getInstance().initializeMyValue();

But here is the problem: you still have 2 instances. One in Singleton and the other in SingletonExtended. If you use:
Singleton.getInstance().initializeMyValue();
and trace:
SingletonExtended.getInstance().myValueNotInitialized
you will get null, which is normal.

This doesn't make a lot of sense for a Singleton, does it?

The solution I found is updating the Singleton instance with the SingletonExtended one.

In the Singleton, I'm now able to update the instance:

Actionscript:
  1. public function updateInstance(instance:Singleton):void {
  2.     if (instance != null && instance is Singleton) _instance = instance;
  3.     else throw new Error("Incorrect Singleton update");
  4. }

And in the subclass SingletonExtended, I change the getInstance method:

Actionscript:
  1. public static function getInstance():SingletonExtended {
  2.     Singleton.getInstance().updateInstance(_instance);
  3.     return _instance;
  4. }

This is doing the job I needed, a fully Extended Singleton with no errors accessing the super or he subclass.

I tried to break it, but if it is possible, I didn't find the hole. And if you have a better solution, I'd be very happy to see it.

You can download the source by clicking here, or see the classes below.

The main class:

Actionscript:
  1. package {
  2.    
  3.     import flash.display.Sprite;
  4.    
  5.     /**
  6.      * <b>Author:</b> Romuald Quantin - <a href="http://www.soundstep.com/" target="_blank">www.soundstep.com</a><br />
  7.      * <b>Class version:</b> 1.0<br />
  8.      * <b>Actionscript version:</b> 3.0<br />
  9.      * <b>Date:</b> 11-2008<br />
  10.      */
  11.     
  12.     public class Main extends Sprite {
  13.        
  14.         //------------------------------------
  15.         // private properties
  16.         //------------------------------------
  17.        
  18.         //------------------------------------
  19.         // public properties
  20.         //------------------------------------
  21.        
  22.         //------------------------------------
  23.         // constructor
  24.         //------------------------------------
  25.        
  26.         public function Main() {
  27.            
  28.             trace("--- public properties ---");
  29.             trace(Singleton.getInstance().singletonValue + ">>> from Singleton");
  30.             trace(SingletonExtended.getInstance().singletonValue + ">>> from SingletonExtended");
  31.             trace(SingletonExtended.getInstance().singletonExtendedValue + ">>> from SingletonExtended");
  32.             trace(Singleton.getInstance().singletonValue + ">>> from Singleton");
  33.            
  34.             trace("--- access to public methods ---");
  35.             trace(Singleton.getInstance().publicSingletonMethod() + ">>> from Singleton");
  36.             trace(SingletonExtended.getInstance().publicSingletonMethod() + ">>> from SingletonExtended");
  37.             trace(SingletonExtended.getInstance().publicSingletonExtendedMethod() + ">>> from SingletonExtended");
  38.            
  39.             trace("--- access to private methods ---");
  40.             trace(Singleton.getInstance().accessPrivateSingletonMethod() + ">>> from Singleton");
  41.             trace(SingletonExtended.getInstance().accessPrivateSingletonMethod() + ">>> from SingletonExtended");
  42.             trace(SingletonExtended.getInstance().accessPrivateSingletonExtendedMethod() + ">>> from SingletonExtended");
  43.            
  44.             trace("--- access to protected and overriden methods ---");
  45.             trace(Singleton.getInstance().accessProtectedSingletonMethod() + ">>> from Singleton");
  46.             trace(SingletonExtended.getInstance().accessProtectedSingletonMethod() + ">>> from SingletonExtended");
  47.             trace(SingletonExtended.getInstance().accessOverridenSingletonExtendedMethod() + ">>> from SingletonExtended");
  48.            
  49.             trace("--- value not initialized ---");
  50.             trace("before = ", Singleton.getInstance().myValueNotInitialized);
  51.             Singleton.getInstance().initializeMyValue(); // or SingletonExtended.getInstance().initializeMyValue();
  52.             trace("after = ", Singleton.getInstance().myValueNotInitialized);
  53.            
  54.             // this will generate errors
  55.             // as you can't instantiate twice a Singleton or a sublass of Singleton
  56.            
  57.             //var s1:Singleton = new Singleton();
  58.             //var s2:SingletonExtended = new SingletonExtended();
  59.            
  60.         }
  61.        
  62.         //
  63.         // PRIVATE, PROTECTED
  64.         //________________________________________________________________________________________________
  65.        
  66.         //
  67.         // PUBLIC
  68.         //________________________________________________________________________________________________
  69.        
  70.     }
  71. }

The Singleton class:

Actionscript:
  1. package {
  2.  
  3.     import flash.utils.getQualifiedClassName;
  4.     import flash.utils.getQualifiedSuperclassName;
  5.  
  6.     /**
  7.      * <b>Author:</b> Romuald Quantin - <a href="http://www.soundstep.com/" target="_blank">www.soundstep.com</a><br />
  8.      * <b>Class version:</b> 1.0<br />
  9.      * <b>Actionscript version:</b> 3.0<br />
  10.      * <b>Date:</b> 11-2008<br />
  11.      */
  12.     
  13.     public class Singleton {
  14.        
  15.         //------------------------------------
  16.         // private properties
  17.         //------------------------------------
  18.        
  19.         private static var _instance:Singleton = new Singleton();
  20.         private static var _className:String = getQualifiedClassName(super);
  21.        
  22.         private var _myValueNotInitialized:String;
  23.        
  24.         //------------------------------------
  25.         // public properties
  26.         //------------------------------------
  27.        
  28.         public var singletonValue:String = "Singleton value";
  29.        
  30.         //------------------------------------
  31.         // constructor
  32.         //------------------------------------
  33.        
  34.         public function Singleton() {
  35.             if (_instance != null && getQualifiedSuperclassName(this) != _className) throw new Error("Singleton is obviously... Singleton.");
  36.         }
  37.        
  38.         //
  39.         // PRIVATE, PROTECTED
  40.         //________________________________________________________________________________________________
  41.        
  42.         private function privateSingletonMethod():String {
  43.             return "privateSingletonMethod";
  44.         }
  45.        
  46.         protected function protectedSingletonMethod():String {
  47.             return "protectedSingletonMethod";
  48.         }
  49.        
  50.         //
  51.         // PUBLIC
  52.         //________________________________________________________________________________________________
  53.        
  54.         public function initializeMyValue():void {
  55.             _myValueNotInitialized = "I am initialized";
  56.         }
  57.        
  58.         public function updateInstance(instance:Singleton):void {
  59.             if (instance != null && instance is Singleton) _instance = instance;
  60.             else throw new Error("Incorrect Singleton update");
  61.         }
  62.  
  63.         public static function getInstance():Singleton {
  64.             return _instance;
  65.         }
  66.        
  67.         public function publicSingletonMethod():String {
  68.             return "publicSingletonMethod value";
  69.         }
  70.        
  71.         public function accessPrivateSingletonMethod():String {
  72.             return privateSingletonMethod();
  73.         }
  74.        
  75.         public function accessProtectedSingletonMethod():String {
  76.             return protectedSingletonMethod();
  77.         }
  78.        
  79.         public function get myValueNotInitialized():String {
  80.             return _myValueNotInitialized;
  81.         }
  82.     }
  83. }

The SingletonExtended class:

Actionscript:
  1. package {
  2.  
  3.     /**
  4.      * <b>Author:</b> Romuald Quantin - <a href="http://www.soundstep.com/" target="_blank">www.soundstep.com</a><br />
  5.      * <b>Class version:</b> 1.0<br />
  6.      * <b>Actionscript version:</b> 3.0<br />
  7.      * <b>Date:</b> 11-2008<br />
  8.      */
  9.     
  10.     public class SingletonExtended extends Singleton {
  11.        
  12.         //------------------------------------
  13.         // private properties
  14.         //------------------------------------
  15.        
  16.         private static var _instance:SingletonExtended = new SingletonExtended();
  17.        
  18.         //------------------------------------
  19.         // public properties
  20.         //------------------------------------
  21.        
  22.         public var singletonExtendedValue:String = "SingletonExtended value";
  23.        
  24.         //------------------------------------
  25.         // constructor
  26.         //------------------------------------
  27.        
  28.         public function SingletonExtended() {
  29.             if (_instance != null) throw new Error("SingletonExtended is obviously also... Singleton.");
  30.         }
  31.        
  32.         //
  33.         // PRIVATE, PROTECTED
  34.         //________________________________________________________________________________________________
  35.        
  36.         private function privateSingletonExtendedMethod():String {
  37.             return "privateSingletonExtendedMethod";
  38.         }
  39.        
  40.         override protected function protectedSingletonMethod():String {
  41.             return "protectedSingletonMethod overriden in SingletonExtended, value in super.protectedSingletonMethod(): " + super.protectedSingletonMethod();
  42.         }
  43.        
  44.         //
  45.         // PUBLIC
  46.         //________________________________________________________________________________________________
  47.        
  48.         public static function getInstance():SingletonExtended {
  49.             Singleton.getInstance().updateInstance(_instance);
  50.             return _instance;
  51.         }
  52.        
  53.         public function publicSingletonExtendedMethod():String {
  54.             return "publicSingletonExtendedMethod value";
  55.         }
  56.        
  57.         public function accessPrivateSingletonExtendedMethod():String {
  58.             return privateSingletonExtendedMethod();
  59.         }
  60.        
  61.         public function accessOverridenSingletonExtendedMethod():String {
  62.             return protectedSingletonMethod();
  63.         }
  64.    
  65.     }
  66. }

Vote in HexoSearch

Comments 2 Comments »

The ScrollPane component is a nice tool to use if you need to scroll a content or a list with more than text.

If you like to have everything a bit "tweened" in the sites you developed, you will feel the scroll movement of the scrollpane a bit straightforward.

There is an easy way to get this done.

When the user is scrolling the content with the scrollbar of the ScrollPane, the component dispatch an event:

ScrollEvent.SCROLL

The idea is to stop the movement of the content when this event is dispatched using:

e.stopImmediatePropagation()

And then handle the scrolling using a tweener.

I made an simple example with the CanvasUI class I built as it is using a ScrollPane component for the content, but you can use this code for a normal ScrollPane instance.

Here is the demo and the source, code of the main class below for a quick look.

Actionscript:
  1. package {
  2.  
  3.     import flash.display.Sprite;
  4.     import fl.events.ScrollEvent;
  5.     import fl.containers.ScrollPane;
  6.     import fl.controls.ScrollBarDirection;
  7.     import gs.TweenMax;
  8.    
  9.     import com.soundstep.ui.layouts.*; 
  10.     import com.soundstep.ui.*; 
  11.  
  12.     /**
  13.      * <b>Author:</b> Romuald Quantin - <a href="http://www.soundstep.com/" target="_blank">www.soundstep.com</a><br />
  14.      * <b>Actionscript version:</b> 3.0<br />
  15.      */
  16.     
  17.     public class Main extends Sprite {
  18.  
  19.         //------------------------------------
  20.         // private properties
  21.         //------------------------------------
  22.        
  23.         private var _canvas:CanvasUI;
  24.        
  25.         //------------------------------------
  26.         // public properties
  27.         //------------------------------------
  28.        
  29.        
  30.  
  31.         //------------------------------------
  32.         // constructor
  33.         //------------------------------------
  34.        
  35.         public function Main() {
  36.             _canvas = new CanvasUI();
  37.             addChild(_canvas);
  38.             _canvas.canvasAlpha = .2;
  39.             _canvas.horizontalCenter = 0;
  40.             _canvas.verticalCenter = 0;
  41.             _canvas.width = 300;
  42.             _canvas.height = 300;
  43.             _canvas.addChildUI(new ContentText());
  44.             _canvas.refresh();
  45.             _canvas.scrollPane.addEventListener(ScrollEvent.SCROLL, scrollHandler, true);
  46.         }
  47.        
  48.         //
  49.         // PRIVATE, PROTECTED, INTERNAL
  50.         //________________________________________________________________________________________________
  51.        
  52.         private function scrollHandler(e:ScrollEvent):void {
  53.             e.stopImmediatePropagation();
  54.             switch (e.direction) {
  55.                 case ScrollBarDirection.HORIZONTAL:
  56.                     TweenMax.to(_canvas.scrollPane.content, .5, {x:e.position*-1});
  57.                     break;
  58.                 case ScrollBarDirection.VERTICAL:
  59.                     TweenMax.to(_canvas.scrollPane.content, .5, {y:e.position*-1});
  60.                     break;
  61.             }
  62.         }
  63.        
  64.         // PUBLIC
  65.         //________________________________________________________________________________________________
  66.        
  67.        
  68.        
  69.     }
  70. }

Vote in HexoSearch

Comments 2 Comments »

I had to get an AIR application without the OS window, let's say windowless or chromeless.

I needed to be able, with my own graphics, to minimize, restore, maximize, close, close in the system tray or dock, fullscreen and resize.

You can find several tutorials on Internet (with which I got inspired) but I put all these functionalities in one small example as it is convenient.

You need to set 2 parameters out of the code, in the XML description file:

Actionscript:
  1. <systemChrome>none</systemChrome>
  2. <transparent>true</transparent>

I won’t explain the code, I guess it is easy enough to find out. You can comment if something is not clear for you.

Here is the code of the main mxml file:

Actionscript:
  1. <?xml version="1.0" encoding="utf-8"?>
  2. <mx:WindowedApplication xmlns:mx="http://www.adobe.com/2006/mxml" layout="absolute" showFlexChrome="false" creationComplete="init()">
  3.  
  4. <mx:Script>
  5. <![CDATA[
  6.  
  7. [Embed(source="assets/iconDock.png")]
  8. [Bindable]
  9. public var IconDock:Class;
  10.  
  11. private function init():void {
  12.     registerMovementHandler();
  13.     setDock();
  14. }
  15.  
  16. public function registerMovementHandler():void {
  17.     appCanvas.addEventListener(MouseEvent.MOUSE_DOWN, mouseDrag);
  18.     btResizeBottomRight.addEventListener(MouseEvent.MOUSE_DOWN, resizeWindow);
  19.     btResizeBottomLeft.addEventListener(MouseEvent.MOUSE_DOWN, resizeWindow);
  20.     btResizeTopRight.addEventListener(MouseEvent.MOUSE_DOWN, resizeWindow);
  21.     btResizeTopLeft.addEventListener(MouseEvent.MOUSE_DOWN, resizeWindow);
  22. }
  23.  
  24. public function mouseDrag(e:MouseEvent):void {
  25.     if (e.target == e.currentTarget) stage.nativeWindow.startMove();
  26. }
  27.  
  28. public function resizeWindow(e:MouseEvent = null):void {
  29.     if (e.target == e.currentTarget) {
  30.         var corner:String;
  31.         switch(e.currentTarget){
  32.             case btResizeBottomRight:
  33.                 corner = NativeWindowResize.BOTTOM_RIGHT;
  34.                 break;
  35.             case btResizeBottomLeft:
  36.                 corner = NativeWindowResize.BOTTOM_LEFT;
  37.                 break;
  38.             case btResizeTopRight:
  39.                 corner = NativeWindowResize.TOP_RIGHT;
  40.                 break;
  41.             case btResizeTopLeft:
  42.                 corner = NativeWindowResize.TOP_LEFT;
  43.                 break;
  44.         }
  45.         stage.nativeWindow.startResize(corner);
  46.     }
  47. }
  48.  
  49. public function setDock():void {
  50.     if (NativeApplication.supportsSystemTrayIcon){
  51.         dockProperties();
  52.         SystemTrayIcon(NativeApplication.nativeApplication.icon).menu = dockMenu();
  53.     }
  54. }
  55.  
  56. private function dockProperties():void{
  57.     SystemTrayIcon(NativeApplication.nativeApplication.icon).tooltip = "Soundstep | chromeless window";
  58.     SystemTrayIcon(NativeApplication.nativeApplication.icon).addEventListener(MouseEvent.CLICK, undock);
  59. }
  60.  
  61. private function dockMenu():NativeMenu {
  62.     var menu:NativeMenu = new NativeMenu();
  63.     var open:NativeMenuItem = new NativeMenuItem("Open");
  64.     var close:NativeMenuItem = new NativeMenuItem("Close");
  65.     open.addEventListener(Event.SELECT, undock);
  66.     close.addEventListener(Event.SELECT, closeWindow);
  67.     menu.addItem(open);
  68.     menu.addItem(new NativeMenuItem("",true));
  69.     menu.addItem(close);
  70.     return menu;
  71. }
  72.  
  73. public function dock():void {
  74.     stage.nativeWindow.visible = false;
  75.     NativeApplication.nativeApplication.icon.bitmaps = [new IconDock() as Bitmap];
  76. }
  77.  
  78. public function undock(evt:Event):void {
  79.     stage.nativeWindow.visible = true;
  80.     stage.nativeWindow.orderToFront();
  81.     NativeApplication.nativeApplication.icon.bitmaps = [];
  82. }
  83.  
  84. public function closeWindow(e:Event = null):void {
  85.     stage.nativeWindow.close();
  86. }
  87.  
  88. public function setFullscreen():void {
  89.     var state:String = (stage.displayState == StageDisplayState.FULL_SCREEN) ? StageDisplayState.NORMAL : StageDisplayState.FULL_SCREEN;
  90.     stage.displayState = state;
  91. }
  92.  
  93. ]]>
  94. </mx:Script>
  95.  
  96. <mx:Canvas right="0" left="0" top="0" bottom="0" backgroundColor="#CF3232" id="appCanvas">
  97.  
  98.     <mx:Label buttonMode="true" mouseChildren="false" text="Min" top="10" color="#000000" id="btMin" click="minimize()" horizontalCenter="58"/>
  99.     <mx:Label buttonMode="true" mouseChildren="false" text="Max" top="10" color="#000000"  id="btMax" click="maximize()" horizontalCenter="-45"/>
  100.     <mx:Label buttonMode="true" mouseChildren="false" text="Close" top="10" color="#000000" id="btClose" click="closeWindow()" horizontalCenter="96"/>
  101.     <mx:Label buttonMode="true" mouseChildren="false" text="Restore" color="#000000" id="btRestore" click="restore()" top="10" horizontalCenter="-91"/>
  102.     <mx:Label buttonMode="true" mouseChildren="false" y="10" text="Tray/Dock" color="#000000" id="btSys" click="dock()" horizontalCenter="8"/>
  103.     <mx:Label buttonMode="true" mouseChildren="false" text="Fullscreen" color="#000000" horizontalCenter="0" bottom="10" id="btFullscreen" click="setFullscreen()"/>
  104.    
  105.     <mx:Canvas width="20" height="20" backgroundColor="#7B0707" borderStyle="none" borderColor="#FFFFFF" id="btResizeBottomRight" themeColor="#494949" right="0" bottom="0" />
  106.    
  107.     <mx:Canvas width="20" height="20" backgroundColor="#7B0707" borderStyle="none" borderColor="#FFFFFF" id="btResizeTopLeft" themeColor="#494949"  left="0" top="0" />
  108.    
  109.     <mx:Canvas width="20" height="20" backgroundColor="#7B0707" borderStyle="none" borderColor="#FFFFFF" id="btResizeBottomLeft" themeColor="#494949" bottom="0" left="0" />
  110.  
  111.     <mx:Canvas width="20" height="20" backgroundColor="#7B0707" borderStyle="none" borderColor="#FFFFFF" id="btResizeTopRight" themeColor="#494949" right="0" top="0" />
  112.  
  113. </mx:Canvas>
  114.    
  115. </mx:WindowedApplication>

You can download the source or install the AIR application:

In order to view this page
You must enable Javascript
And download the Flash Player
get flash player


Vote in HexoSearch

Comments 5 Comments »

I made some experiments on how to easily access to data in a Flash site. It is probably a mix with good and bad ways but I think it is worth having a look.

What I’ve done here is get data with syntax that is similar to what you get using E4X in AS3. For example with XML and E4X you can use syntax like that:

xml..item[2].author.name.text();

I’m not saying that this experiment is a good practice but I want to show you what you can do by extending the Array class and extending the Proxy class in AS3. The Proxy class is the replacement of the __resolve we were using in AS2.

Let’s say we have a website that will load data from a database at the start, for example using AMFPHP or whatever, and we are going to fill this data at run-time.

In my example I have a kind of tree with countries > cities > people.

I would like to be able to loop easily through the data, as well as getting them with a friendly/readable syntax if needed.

In my example, I have a Singleton class that contains all the data. I don’t load the data in my example, I statically fill the class. I will access to the data like that:

Content.data

This will return me a array of data, which will contains an array of countries, each instance of the country array will contains an array of cities, which will contains an array of people, etc…

So I’d like to access to my data like this:

To browse the countries:
Content.data[0]
Content.data[1]

To browse the cities in the countries:
Content.data[0][0]
Content.data[0][1]

To browse the people in the cities:
Content.data[0][0][0]
Content.data[0][0][1]

That’s nice to loop through with a “for each” or whatever. An Array is a pretty nice tool to store data as you get some functions to manage it like push, splice, reverse, etc.

But these arrays have a problem, what if I need to get more info on my countries, like the weather, an ID or the surface of the country? I would like access to more data like that:

Content.data[0].name
Content.data[0].id

This is possible with an Array as it is one of the few classes in AS3 that are dynamic. It means you can set any property at run time. For example MovieClip is dynamic and Sprite is not, try to add properties at run-time on these classes to see the result. Some people are saying that is it a good and bad things. It is easy to use but you don’t know what kind of properties will be added in your Array at run-time.

So you don’t want that, and better, you want to control what kind of data they are going to put in your Array. We will get that by extending the Array class.

There’s a nice explanation here to extends an Array, as well as control the data type your custom Array class will accept.

So far it is not bad, we can easily access to our data, we can have properties on these arrays and finally we know that we will have the right type of content inside.

The other thing I want is access to my data with a nice E4X-like:

Content.data.France.name
Content.data.France.Paris.name

Easy, we just need a property France on this array and it is done. Well, the thing is we don’t know yet what this array will be filled with, so we are talking about dynamic properties. These dynamic properties will have to be added to the array when we create it because we said we want to control and we don’t want people adding their own properties.

How do we do that?

We’re going to use the Proxy class that make able us able to handle dynamic properties and dynamic calling.

We will have a class that will be an array (what you get when you call Content.data), a class for the countries, a class for the cities and a class for the people. The people class won’t be an array.

So we have the classes DataArray, CountryArray and CityArray that are extending the Array class. We will also have a Proxy class (a class that is extending the Proxy one) for each of the Array. I choose to a Proxy class for each Array class as it is easier to understand.

Let’s see a bit of code.

The Singleton Content class

Actionscript:
  1. package com.soundstep.data {
  2.  
  3.     /**
  4.      * <b>Author:</b> Romuald Quantin - <a href="http://www.soundstep.com/" target="_blank">www.soundstep.com</a><br />
  5.      * <b>Class version:</b> 1.0<br />
  6.      * <b>Actionscript version:</b> 3.0<br />
  7.      * <b>Copyright:</b> Free to use and change (except to include in a framework), an notification email will be welcome for a commercial use (just for information).<br />
  8.      * <b>Date:</b> 05-2008<br />
  9.      * <b>Usage:</b> Manage a Section
  10.      * @example
  11.      * <listing version="3.0">
  12.        
  13.      * </listing>
  14.      */
  15.    
  16.     public class Content {
  17.        
  18.         //------------------------------------
  19.         // private properties
  20.         //------------------------------------
  21.        
  22.         private static var content:Content = new Content();
  23.         private static var _data:Data;
  24.        
  25.         //------------------------------------
  26.         // public properties
  27.         //------------------------------------
  28.        
  29.        
  30.        
  31.         //------------------------------------
  32.         // constructor
  33.         //------------------------------------
  34.        
  35.         public function Content() {
  36.             if (content) throw new Error("Content is Singleton and can only be accessed through Content.data");
  37.             if (_data == null) buildData();
  38.         }
  39.        
  40.         //
  41.         // PRIVATE, INTERNAL
  42.         //________________________________________________________________________________________________
  43.        
  44.         private function buildData():void {
  45.             _data = new Data();
  46.            
  47.         }
  48.        
  49.         //
  50.         // PUBLIC
  51.         //________________________________________________________________________________________________
  52.        
  53.         public static function get data():Data {
  54.             return _data;
  55.         }
  56.        
  57.     }
  58.    
  59. }

The Data and DataArray class

The DataArray is extending the Array class. To be able to extend the Array class you need the dynamic keyword before the class.

dynamic public class DataArray extends Array {

We have a private property type Class used to control the Data we will push in our extended Array.

private var dataType:Class;

To control the type pushed we have to overwrite 4 functions: push, concat, splice and unshift, as it is nicely explained in the AS3 documentation.

Here is the code:

Actionscript:
  1. package com.soundstep.data {
  2.  
  3.     /**
  4.      * <b>Author:</b> Romuald Quantin - <a href="http://www.soundstep.com/" target="_blank">www.soundstep.com</a><br />
  5.      * <b>Class version:</b> 1.0<br />
  6.      * <b>Actionscript version:</b> 3.0<br />
  7.      * <b>Copyright:</b> Free to use and change (except to include in a framework), an notification email will be welcome for a commercial use (just for information).<br />
  8.      * <b>Date:</b> 05-2008<br />
  9.      * <b>Usage:</b> Manage a Section
  10.      * @example
  11.      * <listing version="3.0">
  12.        
  13.      * </listing>
  14.      */
  15.    
  16.     dynamic public class DataArray extends Array {
  17.        
  18.         //------------------------------------
  19.         // private properties
  20.         //------------------------------------
  21.        
  22.         private var dataType:Class;
  23.  
  24.         //------------------------------------
  25.         // public properties
  26.         //------------------------------------
  27.                
  28.         //------------------------------------
  29.         // constructor
  30.         //------------------------------------
  31.        
  32.         public function DataArray(...args) {
  33.             dataType = Country;
  34.             for (var i:int=0; i<args.length; i++) this.push(args[i]);
  35.             length = length;
  36.         }
  37.        
  38.         //
  39.         // PRIVATE, INTERNAL
  40.         //________________________________________________________________________________________________
  41.        
  42.         //
  43.         // PUBLIC
  44.         //________________________________________________________________________________________________
  45.        
  46.         AS3 override function push(...args):uint {
  47.             for (var i:* in args) {
  48.                 if (!(args[i] is dataType)) {
  49.                     trace("Error: you must push an Object type Country");
  50.                     args.splice(i,1);
  51.                 }
  52.             }
  53.             return super.push.apply(this, args);
  54.         }
  55.         
  56.         AS3 override function concat(...args):Array {
  57.             var passArgs:DataArray = new DataArray();
  58.             for (var i:* in args) passArgs.push(args[i]);
  59.             return super.concat.apply(this, passArgs);
  60.         }
  61.        
  62.         AS3 override function splice(...args):* {
  63.             if (args.length> 2) {
  64.                 for (var i:int=2; i<args.length; i++) {
  65.                     if (!(args[i] is dataType)) args.splice(i,1);
  66.                 }
  67.             }
  68.             return super.splice.apply(this, args);
  69.         }
  70.         
  71.         AS3 override function unshift(...args):uint {
  72.             for (var i:* in args) {
  73.                 if (!(args[i] is dataType)) args.splice(i,1);
  74.             }
  75.             return super.unshift.apply(this, args);
  76.         }
  77.        
  78.     }
  79.    
  80. }

To create a new DataArray instance, we actually don’t use the DataArray class directly but his Proxy, that will handle the dynamic properties.

I named the class Data, it is what you get with Content.data.

To extend the Proxy class you need to import the class itself and its namespace:

import flash.utils.Proxy;
import flash.utils.flash_proxy;

Proxy is also a dynamic class:

dynamic public class Data extends Proxy {

We have our private var that will be our DataArray instance:

private var _item:DataArray;

To control the properties and method called through our Proxy, we need to override 3 methods (with the namespace flash_proxy):

override flash_proxy function callProperty(methodName:*, ... args):* {
override flash_proxy function getProperty(name:*):* {
override flash_proxy function setProperty(name:*, value:*):void {

When you will call an unknown method, the Proxy class invoke callProperty, and when you will call or set a property (like Content.data.France), the Proxy class invoke getProperty and setProperty.

In my example I trace an Error if you try to set your own property, this is our control. When you get a property, I loop through the DataArray instance to see if I’ve got an item with that name. We could do it with the id or any property of your choice (that is in the DataArray class), and if yes I return it. This is the instance you get by using Content.data.France.

So in brief, when I call Content.data.France, I’m going through the Proxy that is basically managing the dynamic properties added at run-time. The DataArray class is extending the Array class to control the properties and data type.

Here is the code of the Data class:

Actionscript:
  1. package com.soundstep.data {
  2.  
  3.     /**
  4.      * <b>Author:</b> Romuald Quantin - <a href="http://www.soundstep.com/" target="_blank">www.soundstep.com</a><br />
  5.      * <b>Class version:</b> 1.0<br />
  6.      * <b>Actionscript version:</b> 3.0<br />
  7.      * <b>Copyright:</b> Free to use and change (except to include in a framework), an notification email will be welcome for a commercial use (just for information).<br />
  8.      * <b>Date:</b> 05-2008<br />
  9.      * <b>Usage:</b> Manage a Section
  10.      * @example
  11.      * <listing version="3.0">
  12.        
  13.      * </listing>
  14.      */
  15.  
  16.     import flash.utils.Proxy;
  17.     import flash.utils.flash_proxy;
  18.    
  19.     dynamic public class Data extends Proxy {
  20.        
  21.         //------------------------------------
  22.         // private properties
  23.         //------------------------------------
  24.        
  25.         private var _item:DataArray;
  26.        
  27.         //------------------------------------
  28.         // public properties
  29.         //------------------------------------
  30.                
  31.         //------------------------------------
  32.         // constructor
  33.         //------------------------------------
  34.        
  35.         public function Data(...args) {
  36.             _item = new DataArray();
  37.             for (var i:int=0; i<args.length; i++) _item.push(args[i]);
  38.         }
  39.        
  40.         //
  41.         // PRIVATE, INTERNAL
  42.         //________________________________________________________________________________________________
  43.        
  44.         private function getString():String {
  45.             var s:String = "";
  46.             for (var i:uint=0; i<_item.length; i++) {
  47.                 s += "index:" + i + ", id:" + _item[i].id + ", name:" + _item[i].name;
  48.                 if (i <_item.length-1) s += "\n";
  49.             }
  50.             if (_item.length == 0) return _item.name + " is empty";
  51.             else return s;
  52.         }
  53.        
  54.         //
  55.         // PUBLIC
  56.         //________________________________________________________________________________________________
  57.        
  58.         override flash_proxy function callProperty(methodName:*, ... args):* {
  59.             var res:*;
  60.             switch (methodName.toString()) {
  61.                 case 'clear':
  62.                     _item = new DataArray();
  63.                     break;
  64.                 case 'list':
  65.                     trace(getString());
  66.                     break;
  67.                 default:
  68.                     res = _item[methodName].apply(_item, args);
  69.                     break;
  70.             }
  71.             return res;
  72.         }
  73.  
  74.         override flash_proxy function getProperty(name:*):* {
  75.             for each (var i:* in _item) {
  76.                 if (name == i.name) {
  77.                     return i;
  78.                     break;
  79.                 }
  80.             }
  81.             return _item[name];
  82.             throw new Error("ERROR: Property " + name + " not found!");
  83.         }
  84.  
  85.         override flash_proxy function setProperty(name:*, value:*):void {
  86.             trace("ERROR: You can't set your own property!");
  87.         }
  88.        
  89.         public function toString():String {
  90.             return getString();
  91.         }
  92.     }
  93. }

Basically the cities and countries classes are doing the same, the dataType and properties are different, a country is asking a City type and the a city is asking a People type.

For example the CountryArray class asks an id and name to create the array, you have to use a syntax like:

var france:Country = new Country(0, "France");

As it is an Array extended you can still pass more arguments (but they have to be the right type), the type here is City, that is also an Array extended but a city instance is asking an id, a name and weather as parameters:

var france:Country = new Country(0, "France", new City(0, "Paris", "As bad as London!"), new City(1, "Marseille", "More sun than Paris"));

Here is how I fill the Content with some examples:

Actionscript:
  1. //country
  2. var france:Country = new Country(0, "France");
  3. Content.data.push(france);
  4. var uk:Country = new Country(1, "UK");
  5. Content.data.push(uk);
  6.  
  7. // city
  8. var paris:City = new City(0, "Paris", "As bad as London!");
  9. france.push(paris);
  10. france.myvar = "qwe";
  11. var marseille:City = new City(1, "Marseille", "More sun than Paris");
  12. france.push(marseille);
  13. var london:City = new City(0, "London", "Quite bad!");
  14. uk.push(london);
  15. var liverpool:City = new City(1, "Liverpool", "Even worst than London");
  16. uk.push(liverpool);
  17.  
  18. // people
  19. var franck:People = new People(0, "Franck", "Dupont", 29);
  20. paris.push(franck);
  21. var stephane:People = new People(1, "Stephane", "Durand", 42);
  22. paris.push(stephane);
  23. var john:People = new People(0, "John", "Doe", 35);
  24. london.push(john);
  25. var david:People = new People(0, "David", "Doe", 37);
  26. london.push(david);

And finally here is some example to access to your data:

Actionscript:
  1. Content.data.length
  2. Content.data.France.length
  3. Content.data[0].name
  4. Content.data.France.name
  5. Content.data.France[0].name
  6. Content.data.France.Paris.name
  7. Content.data.France.Paris.Franck.name
  8. Content.data[0][0][0].name

I didn’t optimize/clean the classes and as I said, I’m not saying that it is a good way of accessing data in Flash, but it shows you how to control data type, how to extend an Array, how to extend the Proxy class and how to handle properties and methods of a class at low-level.

Download the source.

Vote in HexoSearch

Comments No Comments »