Display List Architecture in Flex - actionscript-3

I'm asked about Display List architecture in Flex at an interview. Later I searched about it but no use. Any help is appreciated.

The Display List is like a tree. Imagine the Stage object as the base of the tree. Think of MovieClips and Sprites that are added to the stage as branches and leaves coming off of the tree. The Display List also serves as the core for the event system in AVM2. Objects that are attached to the DisplayList (that is, they themselves or their parent, parents parent etc end up connecting to the Stage) can "bubble" events through the Display List.
Anyway that's my short little way of explaining it but you can get much more detailed information from these links:
http://www.adobe.com/devnet/flash/quickstart/display_list_programming_as3.html
http://tv.adobe.com/watch/colin-moocks-lost-actionscript-weekend/the-display-list/

seems like the question should really sound as follows:
when you write <s:Application> (or any other SkinnableContainer / UIComponent) in your mxml code -- what is the structure of the resulting display list?
so you should do something like:
<?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" applicationComplete="onAppComplete();">
<fx:Declarations>
<!-- Place non-visual elements (e.g., services, value objects) here -->
</fx:Declarations>
<fx:Script>
<![CDATA[
import flash.display.DisplayObject;
import flash.display.DisplayObjectContainer;
import mx.controls.Alert;
import mx.core.UIComponent;
import spark.components.SkinnableContainer;
private function onAppComplete(e:* = null):void {
trace(parseList(stage));
//Alert.show(parseList(stage));
}
private function parseList(uic:DisplayObjectContainer, prefix:String = '>'):String{
prefix = prefix || '>';
var retStr:String = '';
for (var i:int = 0; i < uic.numChildren; i++ ) {
retStr += prefix + uic.getChildAt(i).name + '\n';
if (uic.getChildAt(i) is DisplayObjectContainer) {
retStr += parseList(uic.getChildAt(i) as DisplayObjectContainer, prefix + '>');
}
}
return retStr;
}
]]>
</fx:Script>
<s:SkinnableContainer>
<s:Panel>
<mx:UIComponent>
</mx:UIComponent>
</s:Panel>
</s:SkinnableContainer>
</s:Application>
(or maybe more complex) and study the output
the code above outputs
>root1
>>NewFile1
>>>ApplicationSkin3
>>>>Group4
>>>>>Group5
>>>>>>SkinnableContainer6
>>>>>>>SkinnableContainerSkin7
>>>>>>>>Group8
>>>>>>>>>Panel9
>>>>>>>>>>PanelSkin10
>>>>>>>>>>>RectangularDropShadow11
>>>>>>>>>>>Group12
>>>>>>>>>>>>Group13
>>>>>>>>>>>>instance36
>>>>>>>>>>>>Group14
>>>>>>>>>>>>>Group15
>>>>>>>>>>>>>>Label16
>>>>>>>>>>>>>>>instance33
>>>>>>>>>>>>>>>instance37
>>>>>>>>>>>>>Group17
>>>>>>>>>>>>>>UIComponent18

Related

Value specified in SortField not being used by ArrayCollection Sort

I saw this earlier question (Flex arraycollection sorting not working) but it doesn't seem to pertain to the issue I am seeing.
I am trying to do a sort of an ArrayCollection using a custom compare function (using the example from here: Alphanumeric Sorting in AS3 )
The problem: It seems that the field name specified in my SortField instance is not being passed to the compare function – instead the objects themselves are. This seems wrong – but maybe I am misunderstanding (this question and the answers are a little confusing: Flex: Sort -- Writing a custom compareFunction?) – what is the point of specifying a field name in the SortField if it isn't going to be used?
A stripped down example is below. I am trying to sort a list of File instances. A trace statement in the compare function confirms that the File instance, not their name properties are being passed as arguments.
Do I need to customize the compare function? That is ** cough ** less that an optimal solution for reusable coding.
Update:
As often happens, I come up with a solution withing 10 minutes of posting a question. In this case using a proxy function. Still, I am wondering why the value specified in SortField isn't being used.
public function customCompare(obj1:*, obj2:*):int
{
return AlphaNumericSort.compare(obj1.name, obj2.name);
}
<?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.collections.ArrayCollection;
import mx.events.FlexEvent;
import spark.collections.Sort;
import spark.collections.SortField;
import utils.AlphaNumericSort;
protected function windowedapplication1_creationCompleteHandler(event:FlexEvent):void
{
var directory:File = File.desktopDirectory.resolvePath("testFolder");
if (directory.exists){
var collection:ArrayCollection;
var obj:*;
var sort:Sort;
var sortField:SortField;
collection = new ArrayCollection(directory.getDirectoryListing());
sort = new Sort();
sortField = new SortField("name");
sortField.compareFunction = AlphaNumericSort.compare;
sort.fields = [sortField];
collection.sort = sort;
collection.refresh();
trace("---------AlphaNumericSort")
for each (obj in collection){
trace(obj.name);
}
trace(" ");
}
}
]]>
</fx:Script>
</s:WindowedApplication>
I have tested your code. It works fine. Only, in your code replace the below line
sortField.compareFunction = AlphaNumericSort.compare;
to sortField.compareFunction = customCompare;

Custom Flex 4 data components won't compile within fx:Declarations tags (and aren't allowed outside them)

I have built an extensive library to render complex data from several XML sources, and have abstracted some of these sources as classes which just extend Object. As an experiment, I began extending XMLListCollection in an attempt to make the data-handling implementation more integrated and Flex-like, but thus far mxmlc does not cooperate with a useful message.
The compilation which generates an error:
(fcsh) mxmlc -use-network=true -omit-trace-statements=false -debug=true xmllist_test.mxml
fcsh: Assigned 1 as the compile target id
Loading configuration file /dev/Flex SDK/frameworks/flex-config.xml
Recompile: xmllist_test.mxml
Reason: The source file wasn't fully compiled.
Files changed: 0 Files affected: 1
xmllist_test.mxml(-1): Error: Incorrect number of arguments. Expected 1.
<?xml version="1.0" encoding="utf-8" ?>
(fcsh)
The offending mxml, xmllist_test.mxml:
<?xml version="1.0" encoding="utf-8" ?>
<!-- xmllist_test -->
<s:Application xmlns:fx="http://ns.adobe.com/mxml/2009"
xmlns:mx="library://ns.adobe.com/flex/mx"
xmlns:s="library://ns.adobe.com/flex/spark"
xmlns:maf="mafComponents.*"
creationComplete="makeItSo()"
backgroundColor="#FFFFFF">
<s:layout>
<s:VerticalLayout/>
</s:layout>
<fx:Script>
<![CDATA[
import mafComponents.examples.*;
public var maf:XML = MafExamples.ghp010; // defined statically in the package
public function makeItSo():void
{
trace('name', maf.#name);
}
]]>
</fx:Script>
<fx:Declarations>
<!-- a comment -->
<mx:XMLListCollection id="mafSource1" source="{maf.block}"/> <!-- no problem -->
<maf:MafXMLListCollection id="mafSource2" metasource="maf}"/> <!-- won't compile -->
</fx:Declarations>
</s:Application>
I included in the above xmllist_test.mxml code an example which works using <mx:XMLListCollection>, but the whole compilation fails at the presence of my custom component <maf:MafXMLListCollection>.
I don't know how to interpret the compiler message, considering that xmllist_test.mxml(-1) seems to indicate an error before lines were counted, and the reporting of the xml declaration line.
I couldn't find any documentation on how to use fx:Declarations in this way, although it is stated as a place reserved for non-visual components, which mine is:
package mafComponents
{
import mx.collections.*;
/**
* An extension of XMLListCollection that specifically serializes the "block" elements of a MAF, while processing other information as well.
**/
public class MafXMLListCollection extends XMLListCollection
{
public var maf:XML;
public var mafXMLList:XMLList;
public var name:String;
private var _metasource:*;
/**
* Process the sequence of "blocks" in datasource to an XMLList to use as the parent class's "source" attribute
**/
public function set metasource(datasource:*):void
{
// multiple options for source, get it to the point of an XML with "maf" at the root
if (datasource is XML)
{
maf = datasource as XML;
}
mafXMLList = maf.block; // this expression returns an XMLList
name = 'MafXMLListCollection_' + maf.#name;
source = mafXMLList;
// do other stuff with the data structure here
// ...
}
/**
* #private
**/
public function get metasource():* { return _metasource; }
public function MafXMLListCollection(datasource:*)
{
super();
metasource = datasource;
// make the main list from the sequence of "block" sections in the XML
trace(name + '.length: ' + length);
}
}
}
Despite this problem, I can use the custom component through actionscript in the <fx:Script> tag without compilation errors. I just don't understand if the MXML compilation fails because I am making a syntactic error, or if my misunderstanding is at the philosophical level and I have attempted something that just isn't implemented.
Thank you in advance for any perspective you might offer on the subject.
1) Since MafXMLListCollection doesn't implement IVisualElement, it can't be included in the visual element declaration (hence the warning about the tag being required).
2) Since MafXMLListCollection has parameters to the constructor, you can't use the MXML format declaration. You must create the variable inside your <Script> block:
public var mafSource2:MafXMLListCollection = new MafXMLListCollection(maf);
Or, you could change MafXMLListCollection to have a default constructor, and use the metasource property (which you're already doing in the MXML).

Weird crash in AIR application

I have a crash that only happens with the installed application I can't make it cvrash in the IDE(Flash Builder debug or run option)
After a long time of commenting and uncomenting code I found the problem and I am posting the code below
<?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"
xmlns:ns="generic_components.*"
creationComplete="windowedapplication1_creationCompleteHandler(event)">
<fx:Script>
<![CDATA[
//import core.Logger;
import mx.controls.Alert;
import mx.events.FlexEvent;
import spark.events.TextOperationEvent;
protected function windowedapplication1_creationCompleteHandler(event:FlexEvent):void
{
//Logger.init();
}
public static function humanFromCamelCase(txt:String):String{
var res:String=txt.charAt(0);
//Logger.write("camel case for "+txt);
for (var i:int=1;i<txt.length;i++)
{
// Logger.write("camel iter "+i);
var c:String=txt.charAt(i);
//Logger.write("camel char is "+c);
if(c==c.toUpperCase())
{
res=res+" "+c;
}
else
res=res+c;
}
return res;
}
protected function test_clickHandler(event:Event):void
{
Alert.show(humanFromCamelCase("CompanyId"));
}
]]>
</fx:Script>
<fx:Declarations>
<!-- Place non-visual elements (e.g., services, value objects) here -->
</fx:Declarations>
<s:layout>
<s:VerticalLayout />
</s:layout>
<s:Button id="test" label="TEST" click="test_clickHandler(event)"/>
</s:WindowedApplication>
Also see a web sample here http://ploscariu.com/crash/TestWeb.html (may be not there in the future)
What is weird about this crash:
1 I have no idea what happens
2 The usual crash handler in the player does not show up
3 is not crashing in the development enviroment IDE
4 if i uncomment those Logger.write then the code works on my machine fine(it could not work on all machines), the Logger.write writes the sting in a file and is placed in another project swf (I did not included the logger code)
I a, assuming that the call to Logger.write can cause a delay or something similar
It is something wrong in my code or the player is buggy? or the compiler??
Any ideas?
Edit:
-is not the logger i use since the error happens when I am not using it like in the sample code or page, no logger the app it crashes
-i get no dialog from Flash with a crash report
This is so incredibly odd!!!! I have NO idea why this happening (yet)... but I have a workaround:
Instead of res=res+c, use res+=c:
public static function humanFromCamelCase(txt:String):String{
var res:String=txt.charAt(0);
for (var i:int=1;i<txt.length;i++)
{
var c:String=txt.charAt(i);
if(c === c.toUpperCase())
{
res += " " + c;
}
else
res += c;
}
return res;
}
I have no idea why you're having an error, however, I would replace the function with this instead:
public static function humanFromCamelCase(txt:String):String{
return txt.replace(/([A-Z])/g, ' $1').replace(/^ /, "");
}
Haven't tested it, but you get the idea. This is a much simpler and faster approach.
I also thought of another way:
public static function humanFromCamelCase(txt:String):String{
return txt.split(/(?=[A-Z])/).join(' ');
}

How to run a function after the canvas has changed in ActionScript 3.0?

Please understand: I am a total beginner at Actionscript and anything like Actionscript, and though I generally have some idea of what I'm doing as a programmer, I'm having some setbacks in self-learning this language and Flex Builder. Right now I'm trying to make a very simple implementation where a label effectively has its text added to multiple times over the first few seconds that the program is run. The problem I'm running into is that I can't just put all that into one function + one call on that function, as changes to the label's text are apparently not seen until that function runs its full course.
So I tried using a viewstack and cloning the canvas a few times, giving each canvas's version of that label a different bit of text. Then I set the initialize function for the viewstack to change the canvases on regular intervals over the first few seconds. But that didn't work either, as the difference isn't seen until the function runs its full course.
So then I tried putting function calls on the individual canvases' initialize attributes, and those functions aren't being called at all apparently.
What the heck? I know this probably isn't even the way that you're supposed to animate something in ActionScript or Flex, but I still would like to know how to approach the problem this way for future reference. What am I missing? Thanks!
As you've noticed, changes to the displayed output of your program can't happen in the middle of executing a function that you've written. ActionScript is single-threaded, which means that none of the framework code that updates the screen can run while your function is running.
If you're interested in learning exactly what happens in order to update the screen, do a search for "flex component lifecycle" and read some of the stuff you find. It's a bit advanced, but it was the thing that really helped me understand how the Flex framework works.
Anyway, on to your real question - how to animate something. There are many ways, but for your case of progressively adding text to a label, I'd probably use the Timer class.
Here is an example:
<?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:Script>
<![CDATA[
import mx.events.FlexEvent;
private var timer:Timer;
private var words:Array = ["The", "quick", "brown", "fox"];
private function startTimer(event:FlexEvent):void
{
timer = new Timer(1000, 1);
timer.addEventListener(TimerEvent.TIMER, updateText);
timer.start();
}
private privatefunction updateText(event:TimerEvent):void
{
theLabel.text += words.shift() + " ";
if (words.length > 0)
{
timer.reset();
timer.start();
}
}
]]>
</fx:Script>
<s:Label id="theLabel" text="" creationComplete="startTimer(event)"/>
</s:Application>
A basic approach would be to use data binding for the label value, and setTimeout() or setInterval() to cause the delay between updates.
Here is an example:
<?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"
initialize="init()"
minWidth="955" minHeight="600">
<fx:Script>
<![CDATA[
[Bindable]
private var displayString:String = "Detonation in ";
private var count:int = 5;
private var timer:uint;
private function init():void {
timer = setInterval(updateDisplay, 1000);
}
private function updateDisplay():void {
displayString += count + ".. ";
if (--count == 0) {
clearInterval(timer);
}
}
]]>
</fx:Script>
<s:Label text="{displayString}"/>
</s:Application>

FlexEvent.APPLICATION_COMPLETE never called in simple app

I've got a really simple flex application, with a main file Rec.mxml:
<?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="215" minHeight="138" width="215" height="138" backgroundAlpha="0.0">
<fx:Script>
<![CDATA[
var rec:LRec = new LRec();
]]>
</fx:Script>
<fx:Declarations>
<!-- Place non-visual elements (e.g., services, value objects) here -->
</fx:Declarations>
</s:Application>
And an AS3 class:
package
{
import mx.core.Application;
import mx.events.FlexEvent;
public class LRec extends Application
{
public function LRec()
{
trace("CONSTRUCTED");
addEventListener(FlexEvent.APPLICATION_COMPLETE, this.mainInit);
}
/**
* After the application startup is complete, debug
*/
public function mainInit(event:FlexEvent):void {
trace("COMPLETE");
}
}
}
The trace ("CONSTRUCTED") is printed, but not "COMPLETE" -- it looks like the FlexEvent.APPLICATION_COMPLETE event is never registering. Any ideas why?
Also, this is the first time I've really done this sort of programming, so if anything else looks wrong, please tell me!
I've updated your code below with some comments on where you were going wrong. If you have any other questions feel free to ask.
Test.mxml
<?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="215" minHeight="138" width="215" height="138" backgroundAlpha="0.0"
initialize="handle_initialize(event)"
>
<fx:Script>
<![CDATA[
import mx.events.FlexEvent;
// Probably want to keep your rec object around
private var rec:LRec;
// Construct your LRec instance in the Application's inititialize state,
// rather than declaring it statically.
protected function handle_initialize(event:FlexEvent):void
{
// Construct a new LRec instance, assign it to our private variable.
this.rec = new LRec();
// The <s:Applicaiton instance we define in this mxml is the object that
// will actually dispatch the applicationComplete event, so we want to
// listen for that here and pass it on to our LRec instance's mainInit
// method when it fires.
this.addEventListener(FlexEvent.APPLICATION_COMPLETE, this.rec.mainInit);
}
]]>
</fx:Script>
<fx:Declarations>
<!-- Place non-visual elements (e.g., services, value objects) here -->
</fx:Declarations>
</s:Application>
LRec.as
package
{
import mx.events.FlexEvent;
// Don't inherit from Application, as you've already defined your application
// in your mxml, and you should have only one Application instance per application.
public class LRec
{
public function LRec()
{
trace("CONSTRUCTED");
// Doesn't need the event listener anymore.
// Do any instantiation needed.
}
/**
* After the application startup is complete, debug
*/
public function mainInit(event:FlexEvent):void {
trace("COMPLETE");
// Do any of the work that needs to wait for the applicationComplete
// event to fire.
}
}
}
Here's a good article (though a bit dated) on the Flex Instantiation Model.