Event issues (not detected) - actionscript-3

I'm quite new to Flex and ActionScript, and I'm trying to do an application whose purpose is simply to be able to dynamically create rectangles on a panel: on mouse down the rectangle is created and updated on mouse move events (left button hold down), then the rectangle is achieved with mouse up.
<?xml version="1.0" encoding="utf-8"?>
<s:WindowedApplication xmlns:fx="http://ns.adobe.com/mxml/2009"
xmlns:s="library://ns.adobe.com/flex/spark"
xmlns:mx="library://ns.adobe.com/flex/mx"
width="550" height="400"
creationComplete="this.onCreationComplete(event);">
<fx:Declarations>
<!-- Place non-visual elements (e.g., services, value objects) here -->
</fx:Declarations>
<fx:Script>
<![CDATA[
import mx.collections.ArrayCollection;
import mx.controls.Alert;
import mx.events.FlexEvent;
import mx.graphics.SolidColor;
import spark.primitives.Graphic;
import spark.primitives.Rect;
public static const WIDTH:int = 480;
public static const HEIGHT:int = 300;
public static const BACKGROUND:int = 0xEFEFEF;
public static const CURRENT_FILL:SolidColor = new SolidColor(0x00AA00, 0.75);
protected var rectangles:ArrayCollection = null;
protected var currentRect:Rect = null;
protected var dragging:Boolean = false;
protected function onCreationComplete(event:FlexEvent):void
{
this.rectangles = new ArrayCollection();
this.sprite.graphics.beginFill(BACKGROUND);
this.sprite.graphics.drawRect(0, 0, this.sprite.width, this.sprite.height);
this.sprite.graphics.endFill();
this.sprite.addEventListener(MouseEvent.MOUSE_DOWN, this.onMouseDown);
this.sprite.addEventListener(MouseEvent.MOUSE_UP, this.onMouseUp);
}
protected function onMouseDown(event:MouseEvent):void
{
this.currentRect = new Rect();
this.currentRect.y = 10;
this.currentRect.height = this.sprite.height - (10 * 2);
this.currentRect.x = event.localX;
this.currentRect.width = 1;
this.panel.addElement(this.currentRect);
this.dragging = true;
this.sprite.addEventListener(MouseEvent.MOUSE_MOVE, this.onMouseMove);
}
protected function onMouseUp(event:MouseEvent):void
{
if (this.dragging)
{
this.sprite.removeEventListener(MouseEvent.MOUSE_MOVE, this.onMouseMove);
this.rectangles.addItem(this.currentRect);
this.dragging = false;
}
}
protected function onMouseMove(event:MouseEvent):void
{
if (this.dragging)
{
this.currentRect.width = event.localX - this.currentRect.x;
}
}
]]>
</fx:Script>
<s:Panel id="panel" x="10" y="10" title="Calendar">
<s:SpriteVisualElement id="sprite" width="{WIDTH}" height="{HEIGHT}" />
</s:Panel>
</s:WindowedApplication>
All works fine but now I want to do some actions when the user clicks (or double clicks, or what you want) on a rectangle. I tried to add an event on each rectangle (this.currentRect.addEventListener(MouseEvent.DOUBLE_CLICK, myMethod) added in onMouseUp), but the corresponding method is never executed...
What's the problem?

Objects drawn with the graphics API are not event dispatchers. So use addElement to add the Spark primitive rects that you're creating but not using in any way (to a container such a Group) instead of using the graphics api to draw the shapes.
You might find it's better, however, to simply have the ArrayCollection contain a bunch of bindable data objects and use a DataGroup with itemRenderers to display the data.

You could keep track of the rectangles you have drawn in a collection and do a hit test with the rectangles on mouse clicks and determine if any rectangle is being clicked on.

Related

How to convert a string to an object

I'm trying to use a sharedObject to coordinate the movement of several objects on the stage between multiple game players. I think that I'm very close but I seem to be having a problem converting a string stored in the sharedObject into an instance of the Ball class.
My problem is in the soSync function.
I think I need to convert into an object the value of 'objectMoved' that is stored in the sharedObject. I can trace the name of the selected object, but I cannot retrieve it as an object.
How do I store the selected object in a sharedObject and then use it to coordinate motion with the other game players?
<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" layout="absolute" creationComplete="init()">
<mx:Script>
<![CDATA[
import mx.core.UIComponent;
public var nc:NetConnection;
private var connectionURL:String = "rtmp://server address...";
public var remoteSO:SharedObject;
private var checker:Ball;
public function init():void{
//Create new checkers; place them and create listeners
for (var i:int = 0; i < 3; i++){
checker = new Ball;
checker.x = 150 + (i * 110);
checker.y = 150;
checker.name = String(i);
this.addChild(checker);
checker.addEventListener(MouseEvent.MOUSE_DOWN,handleMouseDown);
}
// Establish connection to the server
nc = new NetConnection();
//Listener triggered by the NetConnection connection
nc.addEventListener(NetStatusEvent.NET_STATUS, netStatusHandler);
nc.connect(connectionURL);
}
private function netStatusHandler(e:NetStatusEvent):void {
if(e.info.code == "NetConnection.Connect.Success"){
createRemoteSO();
}
}
private function handleMouseDown(e:MouseEvent):void{
//Show which object has been selected
objectInfo.text = "Clicked: "+String(e.currentTarget);
e.currentTarget.startDrag();
e.currentTarget.addEventListener(MouseEvent.MOUSE_MOVE,dragging);
e.currentTarget.addEventListener(MouseEvent.MOUSE_UP,handleMouseUp)
//Update the remote shared object from this client
function dragging(e:MouseEvent):void{
objectInfo.text = "Dragging: "+String(e.currentTarget);
//Set the shared object
remoteSO.setProperty("objectMoved",e.currentTarget.name);
remoteSO.setProperty("x",e.currentTarget.x);
remoteSO.setProperty("y",e.currentTarget.y);
}
function handleMouseUp(e:MouseEvent):void{
e.currentTarget.stopDrag();
objectInfo.text = ""
e.currentTarget.removeEventListener(MouseEvent.MOUSE_MOVE,dragging)
}
}
private function createRemoteSO():void{
// Create reference to the remote shared object
remoteSO = SharedObject.getRemote("remoteSO",nc.uri,false);
remoteSO.connect(nc);
//Listener to handle changes to the remote shared object
remoteSO.addEventListener(SyncEvent.SYNC, soSync);
}
//Called when a change is made to the remote shared object by other clients
private var counter:int;
private function soSync(se:SyncEvent):void {
if(remoteSO.data.objectMoved){
this.getChildByName(remoteSO.data.objectMoved).x = remoteSO.data.x;
this.getChildByName(remoteSO.data.objectMoved).y = remoteSO.data.y;
}else{
trace("Object does not exist")
}
}
]]>
</mx:Script>
<mx:Text x="147" y="51" text="Selected object"/>
<mx:TextArea id="objectInfo" x="237" y="50"/>
</mx:Application>
Ball.mxml
<?xml version="1.0" encoding="utf-8"?>
<mx:UIComponent xmlns:mx="http://www.adobe.com/2006/mxml" creationComplete="init()">
<mx:Script>
<![CDATA[
import mx.events.FlexEvent;
private function init():void{
var child:Shape = new Shape();
child.graphics.beginFill(0xff0000, .5);
child.graphics.drawCircle(0, 0, 50);
child.graphics.endFill();
this.addChild(child);
}
]]>
</mx:Script>
</mx:UIComponent>
I think you could use getChildByName("String/ObjectName here").
So in your case...
this.getChildByName(remoteSO.data.objectMoved).y = remoteSO.data.y;
Alternatively, could you not just add the physical object itself when using setProperty as opposed to the objects name. Like so...
remoteSO.setProperty("objectMoved",e.currentTarget);
Your Ball object seems to be a DisplayObject, which are unable to be saved in a shared object as a whole. You can, however, instantiate a Ball object, read properties out of the SO and assign them to your ball. The properties in question seem to be x and y, and not objectMoved, as your ball's name will most likely be in line of instance389 which does not spell a thing if you lose the naming context, and even if not, you can only find a child by name if it still exists. So, if you have only one object of type Ball, you assign it the X and Y read from the SO, if not, you should store several balls in your SO, so you will instantiate them later and preserve all of their coordinates.

how to achive the string effects like http://www.bcaa.it/

I wanna do a string effect like this website http://www.bcaa.it/
What kind of script or tutorial can I learn from?
Basically I want to achieve same as the website. Have the bouncing string effects, drag the item and move away others item that near it, drag and the sub object follow with easing...
Hey just started coding this up, need something similar for a graph display I'm working on. Here's my start, just two buttons but the idea could be extrapolated/optimized:
<?xml version="1.0" encoding="utf-8"?>
<s:WindowedApplication xmlns:fx="http://ns.adobe.com/mxml/2009"
xmlns:s="library://ns.adobe.com/flex/spark"
xmlns:mx="library://ns.adobe.com/flex/mx"
creationComplete="windowedapplication1_creationCompleteHandler(event)">
<fx:Script>
<![CDATA[
import mx.events.FlexEvent;
private var optimalDistanceUpdateTimer:Timer;
private var optimalDistance:Number = 100;
private var objectUserGrabbed:Button;
private var delayDenominator:Number = 6;
protected function button1_mouseDownHandler(event:MouseEvent):void
{
objectUserGrabbed = event.target as Button;
objectUserGrabbed.startDrag();
}
protected function button1_mouseUpHandler(event:MouseEvent):void
{
objectUserGrabbed.stopDrag();
}
protected function windowedapplication1_creationCompleteHandler(event:FlexEvent):void
{
optimalDistanceUpdateTimer = new Timer(33);
optimalDistanceUpdateTimer.addEventListener(TimerEvent.TIMER, optimalDistanceTickedHandler);
optimalDistanceUpdateTimer.start();
}
private function optimalDistanceTickedHandler(event:TimerEvent):void
{
var targetPoint:Point;
var deltaX:Number;
var deltaY:Number;
if(!objectUserGrabbed)
return;
if(objectUserGrabbed == button1)
{
//Basically here I'm playing of Pythagorean theorem for a 45 degree triangle the x component and the y component are the distance of the hypotenuse over Sqrt(2) for different offsets, radially you'd need to adjust this to compute the target point for each object... would do something like var angleForEach:Number = 360/numObjects; then figure out the target point for each of the objects in a loop var angleForThis = angleForEach*index; (in this example only two objects, no loop needed)
targetPoint = new Point(objectUserGrabbed.x-optimalDistance/Math.SQRT2, objectUserGrabbed.y-optimalDistance/Math.SQRT2);
deltaX = (targetPoint.x-button2.x);
deltaY = (targetPoint.y-button2.y);
button2.move(button2.x+deltaX/delayDenominator, button2.y+deltaY/delayDenominator);
}
else
{
targetPoint = new Point(objectUserGrabbed.x+optimalDistance/Math.SQRT2, objectUserGrabbed.y + optimalDistance/Math.SQRT2);
deltaX = (targetPoint.x-button1.x);
deltaY = (targetPoint.y-button1.y);
button1.move(button1.x+deltaX/delayDenominator, button1.y+deltaY/delayDenominator);
}
lineDrawingArea.graphics.clear();
lineDrawingArea.graphics.lineStyle(1);
lineDrawingArea.graphics.moveTo(button1.x + button1.width/2,button1.y + button1.height/2);
lineDrawingArea.graphics.lineTo(button2.x + button2.width/2,button2.y + button2.height/2);
}
]]>
</fx:Script>
<fx:Declarations>
<!-- Place non-visual elements (e.g., services, value objects) here -->
</fx:Declarations>
<s:Group id="lineDrawingArea"/>
<s:Button id="button1" label="Item 1" mouseDown="button1_mouseDownHandler(event)" mouseUp="button1_mouseUpHandler(event)" x="0" y="0"/>
<s:Button id="button2" label="Item 2" mouseDown="button1_mouseDownHandler(event)" mouseUp="button1_mouseUpHandler(event)" x="0" y="0"/>
</s:WindowedApplication>

Flex: Why are TileList images disappearing on drag?

I'm developing a Flex Air (desktop) application that loads images from the local filesystem into a TileList. The user will then be able to drag (copy) these images out of the list onto another control.
I've finally got the images showing up correctly (and not disappearing after scrolling the TileList) but they seem to disappear from the TileList at the start of a drag operation.
I come from a .NET background and am just learning AS3/Flex, so if you see me using any anti-patterns here, feel free to point them out!
Sample code follows (I've tried to make this as minimal as possible).
Test.mxml:
<?xml version="1.0" encoding="utf-8"?>
<s:WindowedApplication xmlns:fx="http://ns.adobe.com/mxml/2009"
xmlns:s="library://ns.adobe.com/flex/spark"
xmlns:mx="library://ns.adobe.com/flex/mx">
<fx:Script>
<![CDATA[
import mx.collections.ArrayCollection;
import mx.events.FlexEvent;
[Bindable]
protected var _pics:ArrayCollection = new ArrayCollection();
protected function picsList_creationCompleteHandler(event:FlexEvent):void
{
const imageFolderPath:String = "c:\\users\\bbrooks\\Pictures";
var imageDir:File = new File(imageFolderPath);
var imageFiles:Array = imageDir.getDirectoryListing();
for each(var imageFile:File in imageFiles)
{
_pics.addItem(new PictureObject(imageFile.nativePath));
}
// give images a chance to load
var timer:Timer = new Timer(1000);
timer.addEventListener(TimerEvent.TIMER, onTimerExpired);
timer.start();
}
protected function onTimerExpired(event:TimerEvent):void
{
picsList.dataProvider = _pics;
}
]]>
</fx:Script>
<mx:TileList id="picsList" x="0" y="0" width="100%" height="100%" dragEnabled="true" dragMoveEnabled="false"
creationComplete="picsList_creationCompleteHandler(event)" >
<mx:itemRenderer>
<fx:Component>
<mx:Image width="75" height="75" source="{data.image}" />
</fx:Component>
</mx:itemRenderer>
</mx:TileList>
</s:WindowedApplication>
PictureObject.as:
package
{
import flash.display.Loader;
import flash.display.LoaderInfo;
import flash.events.Event;
import flash.net.URLRequest;
import mx.controls.Image;
[Bindable]
[RemoteClass]
public class PictureObject extends Object
{
protected var _image:Image = null;
public function get image():Image { return _image; }
public function set image(newValue:Image):void { _image = newValue; }
public function PictureObject(path:String)
{
var imageLoader:Loader = new Loader();
imageLoader.contentLoaderInfo.addEventListener(Event.COMPLETE, onImageLoaded);
imageLoader.load(new URLRequest(path));
}
protected function onImageLoaded(e:Event):void
{
var imageLoader:Loader = LoaderInfo(e.target).loader;
var bmp:Bitmap = Bitmap(imageLoader.content);
_image = new Image();
_image.smoothBitmapContent = true;
_image.source = new Bitmap(bmp.bitmapData);
_image.width = imageLoader.width;
_image.height = imageLoader.height;
}
}
}
I will mostly reply to your secondary question (guessing it will resolve the primary in one fell swoop): as anti-patterns go, this is not a bad example ;)
You are manually loading the images while the Image class has the loading built-in; just give a URL to its source property and it will automatically load it.
You are setting an Image instance as the source of another Image instance; the source property expects URLs or ByteArrays; I'm surprised it doesn't throw an error; the Image class is probably smart enough to extract the source of the other Image instance.
The Timer is redundant. As said, an Image automatically takes care of loading its content.
The s:Image tag isn't wrapped in an ItemRenderer and hence should have no access to a data property: this code shouldn't even compile.
There's no point in having a Bindable property _pics if you don't plan on binding it.
You use the mx TileList. Why not use the more "modern" Spark version? (This doesn't mean the mx class won't work in a Spark application though).
So you have a lot of deleting to do. You can scrap the PictureObject class altogether; remove the Timer code; and just add the URL Strings to the _pics collection. As a plus you could also replace the mx TileList with a Spark List with TileLayout; something like this:
<s:List id="picsList">
<s:layout>
<s:TileLayout />
</s:layout>
<s:itemRenderer>
<fx:Component>
<s:ItemRenderer>
<s:Image source="{data}" />
</s:ItemRenderer>
</fx:Component>
</s:itemRenderer>
</s:List>
The ActionScript part could be reduced to this:
const imageFolderPath:String = "c:\\users\\bbrooks\\Pictures";
var imageDir:File = new File(imageFolderPath);
var imageFiles:Array = imageDir.getDirectoryListing();
picsList.dataProvider = new ArrayCollection(imageFiles);
Thanks RIAstar. Your answer put me on the track to solving the problem. The new sample code appears below.
The original problem seems to have been with the mx:Image control. Not sure why, but using the s:Image control seems to work.
Granted, this could be accomplished without the PictureObject class at all by simply setting the data source to a list of file paths, but I'm using the image data later and I wanted to get it working by supplying the image data to the custom renderer dynamically.
Test.mxml:
<?xml version="1.0" encoding="utf-8"?>
<s:WindowedApplication xmlns:fx="http://ns.adobe.com/mxml/2009"
xmlns:s="library://ns.adobe.com/flex/spark"
xmlns:mx="library://ns.adobe.com/flex/mx">
<fx:Script>
<![CDATA[
import mx.collections.ArrayCollection;
import mx.events.FlexEvent;
import spark.components.Image;
protected var _pics:ArrayCollection = new ArrayCollection();
protected function picsList_creationCompleteHandler(event:FlexEvent):void
{
const imageFolderPath:String = "c:\\users\\bbbrooks\\Pictures";
var imageDir:File = new File(imageFolderPath);
var imageFiles:Array = imageDir.getDirectoryListing();
for each(var imageFile:File in imageFiles)
{
if (imageFile.extension == "jpg")
{
_pics.addItem(new PictureObject(imageFile.nativePath));
}
}
// give images a chance to load
var timer:Timer = new Timer(1000);
timer.addEventListener(TimerEvent.TIMER, onTimerExpired);
timer.start();
}
protected function onTimerExpired(event:TimerEvent):void
{
picsList.dataProvider = _pics;
}
]]>
</fx:Script>
<s:List id="picsList" x="0" y="0" width="100%" height="100%"
creationComplete="picsList_creationCompleteHandler(event)"
dragEnabled="true" dragMoveEnabled="false">
<s:layout>
<s:TileLayout />
</s:layout>
<s:itemRenderer>
<fx:Component>
<s:ItemRenderer>
<s:Image id="imageDisplay"
width="75" height="75" source="{data.bmp}" />
</s:ItemRenderer>
</fx:Component>
</s:itemRenderer>
</s:List>
</s:WindowedApplication>
PictureObject.as
package
{
import flash.display.Bitmap;
import flash.display.Loader;
import flash.display.LoaderInfo;
import flash.events.Event;
import flash.net.URLRequest;
import mx.controls.Image;
[RemoteClass]
[Bindable]
public class PictureObject extends Object
{
protected var _bmp:Bitmap = null;
public function get bmp():Bitmap { return _bmp; }
public function set bmp(newValue:Bitmap):void { _bmp = newValue; }
public function PictureObject(path:String)
{
var imageLoader:Loader = new Loader();
imageLoader.contentLoaderInfo.addEventListener(Event.COMPLETE, onImageLoaded);
imageLoader.load(new URLRequest(path));
}
protected function onImageLoaded(e:Event):void
{
var imageLoader:Loader = LoaderInfo(e.target).loader;
// create our own copy of the bits in the Loader
var bmp:Bitmap = Bitmap(imageLoader.content);
_bmp = new Bitmap( Bitmap(imageLoader.content).bitmapData );
}
}
}

EFFECT_REPEAT not firing on every iteration of Animate instance when losing focus

I'm not sure if that title is descriptive enough, but here is the basic issue. I have a spark.effects.Animate instance repeating n times with a listener on the EFFECT_REPEAT event. In that event's listener, I'm incrementing a variable. Logic would dictate that if the variable started at 0 and the animation was played with a repeatCount of 3, the variable would be 2 when finished. This works fine, until I focus a different tab. When doing this, on occasion, the repeat event isn't fired/handled (or the animation is just not actually doing the animation) and my count isn't correct when finished.
This is a fully functioning example built against Flex 4.5. To duplicate just click the GO button and maintain focus on the TAB. Then click it again and switch tabs and switch back. The counts don't match.
How can I fix this so that the repeat event is called consistently?
<?xml version="1.0" encoding="utf-8"?>
<s:Application xmlns:fx="http://ns.adobe.com/mxml/2009"
xmlns:s="library://ns.adobe.com/flex/spark"
xmlns:mx="library://ns.adobe.com/flex/mx" width="600" height="400" applicationComplete="application1_applicationCompleteHandler(event)">
<fx:Script>
<![CDATA[
import mx.controls.Image;
import mx.events.EffectEvent;
import mx.events.FlexEvent;
import spark.effects.Animate;
import spark.effects.animation.MotionPath;
import spark.effects.animation.SimpleMotionPath;
private var animate:Animate;
private var someCounter:int = 0;
protected function application1_applicationCompleteHandler(event:FlexEvent):void
{
// Create the graphic
var img:Image = new Image();
img.source = "http://www.google.com/intl/en_com/images/srpr/logo3w.png";
// Add the graphic
addElement( img );
// Create the motion path
var smp:SimpleMotionPath = new SimpleMotionPath();
smp.property = "x";
smp.valueFrom = 0;
smp.valueTo = this.width - 275;
// Add the motion path to a Vector
var paths:Vector.<MotionPath> = new Vector.<MotionPath>();
paths.push( smp );
// Create the animation
animate = new Animate();
animate.easer = null;
animate.target = img;
animate.duration = 150;
animate.repeatCount = 15;
animate.motionPaths = paths;
animate.addEventListener( EffectEvent.EFFECT_REPEAT, animate_effectRepeatHandler );
animate.addEventListener( EffectEvent.EFFECT_END, animate_effectEndHandler );
}
private function animate_effectRepeatHandler( event:EffectEvent ):void
{
lblCounter.text = someCounter.toString();
someCounter++;
}
private function animate_effectEndHandler( event:EffectEvent ):void
{
lblCounter.text = someCounter.toString(); // Sometimes doesn't equal animate.repeatCount - 1
}
protected function button1_clickHandler(event:MouseEvent):void
{
if( !animate.isPlaying )
{
someCounter = 0;
animate.play();
}
}
]]>
</fx:Script>
<mx:Label id="lblCounter" horizontalCenter="0" bottom="50" width="150" height="50" textAlign="center" />
<mx:Button horizontalCenter="0" bottom="0" label="GO" width="150" height="50" click="button1_clickHandler(event)" />
</s:Application>

How can I access child members of a tabNavigator created via ActionScript at run time?

I am creating a tabNavigator object in mxml.
TabNavigator contains navigatorContent objects.
Each NavigatorContent further contains multiple hGroups with three radio buttons in it.
All these elements are populated in the tabNavigator via actionScript code dynamically.
I need to select the second radio button within an hgroup, but am not sure how to do this.
<mx:TabNavigator id="tabNav" height="100" width="500" creationComplete="init();" creationPolicy="all">
</mx:TabNavigator>
private function init():void
{
for(var i:int=0;i<=int(arrColl_items[arrColl_items.length - 1][1]);
i++)
{
//after reading from xml var navContent:NavigatorContent = new NavigatorContent();
for (var j:int=0;j<arrColl_items.length;j++)
{
if(arrColl_items[j][1] == i)
{
var hgrp:HGroup = new HGroup();
hgrp.id = String(arrColl_items[j][0]);
var rdBut1:RadioButton=new RadioButton();
hgrp.addElement(rdBut1);
rdBut1.addEventListener(MouseEvent.CLICK, setrdBut1);
var rdBut2:RadioButton=new RadioButton();
hgrp.addElement(rdBut2);
rdBut2.addEventListener(MouseEvent.CLICK, setrdBut2);
var rdBut3:RadioButton=new RadioButton();
hgrp.addElement(rdBut3);
rdBut3.addEventListener(MouseEvent.CLICK, setrdBut3);
}
}
navContent.addElement(hgrp);
tabNav.addChildAt(navContent,i);
}
}
Can anyone please help out on this?
Regards
Aparna
you did not post the data structure, i hope i got it right. The following demo creates and populates a TabNavigator with three NavigatorContent instances containing series of RadioButtons that can be selected using the method 'getHGroupById'.
I am sure it is possible to realize something like this using Bindable Data and ItemRenderes, probably the better solution.
*Nicholas
The Application:
<?xml version="1.0" encoding="utf-8"?>
<s:Application xmlns:fx="http://ns.adobe.com/mxml/2009"
xmlns:s="library://ns.adobe.com/flex/spark"
xmlns:mx="library://ns.adobe.com/flex/mx" minWidth="955" minHeight="600">
<fx:Declarations>
<!-- Place non-visual elements (e.g., services, value objects) here -->
</fx:Declarations>
<mx:TabNavigator id="tabNav" height="300" width="300" creationComplete="__init();" creationPolicy="all">
</mx:TabNavigator>
<fx:Script>
<![CDATA[
import mx.collections.ArrayCollection;
import spark.components.NavigatorContent;
import spark.components.VGroup;
/**
* The Data Structure, as I understood it
* perhaps you have to adapt the code if
* this does not match your desired structure
* or hierarchy
* */
private var arrColl_items:ArrayCollection = new ArrayCollection(
[
new ArrayCollection(
// 1st NavigatorContent
[
{id:"0",label:"HGroup_1.1"},
{id:"1",label:"HGroup_1.2"}
]
),
new ArrayCollection(
// 2nd NavigatorContent
[
{id:"2",label:"HGroup_2.1"},
{id:"3",label:"HGroup_2.2"},
{id:"4",label:"HGroup_2.3"}
]
),
new ArrayCollection(
// 3rd NavigatorContent
[
{id:"5",label:"HGroup_3.2"},
{id:"6",label:"HGroup_3.3"},
{id:"7",label:"HGroup_3.4"},
{id:"8",label:"HGroup_3.5"},
{id:"9",label:"HGroup_3.5"}
]
)
]
);
/**
* Invoked on creationComplete
* */
private function __init():void
{
// lets add some navigatorContent
for(var i:int=0;i<arrColl_items.length;i++){
// create the navigatorContent
var navContent:NavigatorContent = new NavigatorContent();
navContent.label = "navContent_"+i;
// add a VGroup
var vgrp:VGroup = new VGroup();
vgrp.id = "vGroup";
// and now we add custom HGroup Components called MyHGroup
for (var j:int=0;j<arrColl_items[i].length;j++)
{
var hgrp:MyHGroup = new MyHGroup();
hgrp.id = arrColl_items[i][j].id;
hgrp.label.text = arrColl_items[i][j].label;
vgrp.addElement(hgrp);
}
navContent.addElement(vgrp);
tabNav.addElementAt(navContent,i);
}
// Accessing the radioButtons is now possible
// using the getHGroupById Method
getHGroupById("0").rb1.selected = true;
getHGroupById("1").rb2.selected = true;
getHGroupById("3").rb3.selected = true;
getHGroupById("7").rb1.selected = true;
// I added a RadioGroup within MyHGroup, lets read the selectedValue
trace(getHGroupById("0").rbGroup.selectedValue);
}
/**
* getHGroupById
* Method that runs through the Data Structure
* and returns a MyHGroup Class with the given id
* #param $id:String The id of the MyHGroup Class you want to fetch
* #return MyHGroup or null if non existent
*
* */
public function getHGroupById($id:String):MyHGroup{
// running through the NavigatorContent Instances
for(var i:uint=0; i<tabNav.numElements; i++){
var navContent:NavigatorContent = NavigatorContent(tabNav.getElementAt(i));
// running through the HGroups within a VGroup
for(var j:uint=0; j<VGroup(navContent.getElementAt(0)).numElements; j++){
var hgrp:MyHGroup = VGroup(navContent.getElementAt(0)).getElementAt(j) as MyHGroup;
if(hgrp.id==$id)return hgrp;
}
}
return null;
}
]]>
</fx:Script>
</s:Application>
Finally the MyHGroup Component used in this example. Create a new MXML File name MyHGroup.mxml and paste the following code.
<?xml version="1.0" encoding="utf-8"?>
<!-- Create a new MXML File name MyHGroup and add this code -->
<s:HGroup xmlns:fx="http://ns.adobe.com/mxml/2009"
xmlns:s="library://ns.adobe.com/flex/spark"
xmlns:mx="library://ns.adobe.com/flex/mx" width="200" height="20" paddingLeft="10" >
<fx:Declarations>
<!-- The RadioGroup the Buttons will be linked with -->
<s:RadioButtonGroup id="rbGroup"/>
</fx:Declarations>
<!-- Some fancy label -->
<s:Label id="label" height="20" verticalAlign="middle"/>
<!-- Your Radio Buttons -->
<s:RadioButton id="rb1" group="{rbGroup}"/>
<s:RadioButton id="rb2" group="{rbGroup}"/>
<s:RadioButton id="rb3" group="{rbGroup}"/>
</s:HGroup>