Profile

Top tags

flex   actionscript-3   flex4   flash   flex4.5   air   spark   actionscript   flex3   flash-builder   flexbuilder   function   introspection   skin   itemrenderer   sqlite   blazeds   list   php   mxml   adobe   coldfusion   java   custom-component   mobile   datagrid   json   empty   dynamic   preload  

Recently answered questions

Function binding not set after model is injected

Question

I have a CustomDataGrid that extends from DataGrid and CustomDataGridColumn that extends from DataGridColumn.

CustomDataGridColumn has member variables of type Function.

Inside my view, I inject a presentation model using parsley.

The code is as follows:

<fx:Declarations> 
        <spicefactory:Configure/> 
    </fx:Declarations> 

<fx:Script> 

        [Inject(id="associatedDocumentsPM")] 
        [Bindable] 
        public var model:AssociatedDocumentsPM; 


</fx:Script> 

   <customDataGrid:CustomDataGrid id="AssocDocGrid" 
                                   width="100%" height="{(documentDataList.length+2)*20}" 
                                   doubleClickEnabled="true" enabled="{modeHandler.appEnable}" 
                                   dataP="{documentDataList}" 
                                   sortableColumns="false"> 
        <customDataGrid:columnList> 
            <customDataGrid:CustomDataGridColumn 
                textAlign="left" 
                dataFieldIdentifier="documentName" 
                headerText="Document Type" 
                modifyLabelField="{model.modifyLabelField}" 
                dataField="documentName" 
                isNaNZero="true" 
                showDataTips="true" 
                editable="false"/> 
                ...more columns here...  
       </customDataGrid:columnList>
    </customDataGrid:CustomDataGrid>

The AssociatedDocumentsPM has functions defined and these are set in the columns.

One example being for attribute modifyLabelField="{model.modifyLabelField}"

CustomDataGridColumn.myLabelField is of type Function. myLabelField inside AssociatedDocumentsPM is a public function.

The Parsley Context file is in the parent of the above file and declares the PM as follows:

AssocDocPMFactory is a class with a sole function decorated with [Factory].

So the problem is the following:

When I debug the application and check the columnList of the DataGrid, the variable modifyLabelField is null.

Are function bindings treated differently than variables? I'm using Flex 4.5.1 together with Parsley 2.4.1

I understand that injection could happen after creationComplete is invoked but I thought the binding would take care of that.

I have a feeling that the model - the PM - is null until much much later and the function binding is not triggered.

I tried to use FastInject as well but to no avail.

Is this a problem with function pointers and Flex binding?

Answer  (has 0 votes)

No it isn't. If you have these kind of doubts, it's always a good idea to quickly set up a simple isolated test situation that verifies your assumption. I created the following to test yours:

<s:Application xmlns:fx="http://ns.adobe.com/mxml/2009" 
               xmlns:s="library://ns.adobe.com/flex/spark" 
               creationComplete="onCreationComplete()" >

    <fx:Script>
        <![CDATA[
            private function onCreationComplete():void {
                test = function(item:*):String {
                    return "AAA";
                }
            }

            [Bindable]
            private var test:Function;
        ]]>
    </fx:Script>

    <s:List labelFunction="{test}">
        <s:dataProvider>
            <s:ArrayList>
                <fx:String>A</fx:String>
                <fx:String>B</fx:String>
                <fx:String>C</fx:String>
            </s:ArrayList>
        </s:dataProvider>
    </s:List>

</s:Application>

If the test Function variable is declared Bindable, you'll see 3 times "AAA". If you remove the Bindable metadata, you'll see "A", "B", "C".

So clearly binding works with function pointers too (and you'll have to look elsewhere to find your nullpointer).

Adobe Air - Analytics

Question

I'm soon to be launching an Adobe AIR desktop app. To make the best out of future updates I need to get analytics of which features get used the most and which not.

How to track what the user clicks?

Answer  (has 1 votes)

As I said in the comments: List is not a container. You cannot just add children to it. You should add data objects to its dataProvider. Basically the whole ResultFill method should be reduced to this:

dragDropLeft.dataProvider = new ArrayCollection(arr);

The ItemRenderers that represent this data will be created internally by the List component. Inside your custom ItemRenderer you can now access this data through the data property, so it would become something like this:

<s:ItemRenderer xmlns:fx="http://ns.adobe.com/mxml/2009" 
                xmlns:s="library://ns.adobe.com/flex/spark" 
                autoDrawBackground="true">

     <s:HGroup x="5" y="5" width="350" height="150" 
              horizontalAlign="center" verticalAlign="middle">
         <s:Image source="{data.Picture1}" width="100" height="100"/>
        <s:TextArea text="{data.Common_Name}" height="141" editable="false" />
     </s:HGroup> 
</s:ItemRenderer>

Note that I am assuming that the properties of TreeClass_Full are bindable for this example.

Adobe Air: need help transferring data from sqlite to components

Question

I have successfully received data from sqlite. I see that the data appear in trace function, however I am having a problem with displaying these data correctly. I think it has something to do with binding objects. I must be missing something somewhere, so please correct where I am wrong. Also, this question is actually a continuation of Adobe Air: drag & drop grouped components

Anyway, here is my ItemRenderer:

<?xml version="1.0" encoding="utf-8"?>
<s:ItemRenderer xmlns:fx="http://ns.adobe.com/mxml/2009" 
                xmlns:s="library://ns.adobe.com/flex/spark" 
                xmlns:mx="library://ns.adobe.com/flex/mx" 
                autoDrawBackground="true">

    <fx:Script>

        [Bindable]
        public var tree:TreeClass_Full;

        [Bindable]
        public var dataText:String = "empty";

        public function setTest():void{
            resultTextArea.text = "AAA";
        }
    </fx:Script>
    <s:HGroup x="5" y="5" width="350" height="150" horizontalAlign="center" verticalAlign="middle">
        <mx:Image id = "resultImage" width="100" height="100"/>
        <s:TextArea id="resultTextArea" height="141" editable="false"
                    text = "{tree.Common_Name}"/>
    </s:HGroup> 
</s:ItemRenderer>

Here is the function which will be invoked after sqlite query is successful:

[Bindable]
public var dragDropLeft:ArrayCollection = new ArrayCollection();
[Bindable]
public var dragDropRight:ArrayCollection = new ArrayCollection();

protected function ResultFill():void
{
    // TODO Auto-generated method stub
    if (arr != null){
        for (var i:int = 0; i < arr.length; ++i){
            var tc:TreeClass_Full = arr[i];
            var rr:resultRenderer = new resultRenderer();
            rr.tree = tc;
            trace("--Common Name:" + tc.Common_Name);               

            rr.dataText = tc.Common_Name;
            rr.resultImage.source = tc.Picture1;
            rr.resultTextArea.text = tc.Common_Name;

            trace("----Common Name:" + rr.resultTextArea.text);

            dragDropLeft.addItem(rr);

        }
    }
}

After the sqlite query is successful, the above function will be invoked. This is where I put in the information of my Object (my ItemClass from sqlite) into my ItemRenderer.

My ItemRenderer has two components: Image and TextArea. sqlite contains the respective image, which will be used for Image. For TextArea, all the displayable text from the database will be put there - meaning strings from multiple fields of the database will all be put together there. (but for now, I just want only one field in there, which is Common_Name)

After that, I put these ItemRenderers into my list (dragDropLeft, in this case). However, the data does not appear on the program. Yet, trace function outputs the text correctly.

I've tried a few things and I left some of the codes intact, and all of them yield the same result: the text in the TextArea does not change at all. What have I forget here?

UPDATE:

This code here covers the place that I used my Bindable ArrayCollection:

        <s:HGroup width="100%" height="85%" verticalAlign="middle">
            <s:List dataProvider="{dragDropLeft}" width = "45%" height = "95%"
                    dragEnabled="true" dragMoveEnabled="true" dropEnabled="true"
                    itemRenderer="resultRenderer"/>
            <s:List dataProvider="{dragDropRight}" width = "45%" height = "95%" 
                    dragEnabled="true" dragMoveEnabled="true" dropEnabled="true" 
                    itemRenderer="resultRenderer"/>
        </s:HGroup>

Basically, I tried to manipulate my ItemRenderer on my own by giving it values from sqlite, but from one of the commentors, it seems this is not correct. So how do we do this? How can we send in the data to the ItemRenderer objects that will be added in the list?

Answer  (accepted and has 0 votes)

If you dont mind doing it the hard way, I have two options for you:

  1. Pixel Bender: a tool originally designed for creating complex and CPU-intensive graphic filters and offload those calculations to the hardware. But it can be used for number crunching too. Here's an article that covers that topic: Using Pixel Bender with Flash Builder 4 as a number crunching engine. The language may not be like anything you're used to. I had a hard time wrapping my head around it.
  2. Alchemy: a tool that compiles C or C++ code so it can be executed in the Flash VM. I am not certain how much performance can be gained for simple number crunching, but if you know C, this might be a path to investigate.

Flex: Why are TileList images disappearing on drag?

Question

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;
        }
    }
}

Answer  (accepted and has 0 votes)

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 ;)

  1. 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.
  2. 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.
  3. The Timer is redundant. As said, an Image automatically takes care of loading its content.
  4. 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.
  5. There's no point in having a Bindable property _pics if you don't plan on binding it.
  6. 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);

Adding calculation power to flex application

Question

I have been tasked with making several flex-driven visualizations of immense excel spreadsheets. The client wants the finished product to be as self-contained as possible. The problem being that flex doesn't offer as much computing horsepower as is needed. Is there an easy (or not easy) way to accomplish this. I am just trolling for pointers. Thanks in advance!

Answer  (accepted and has 3 votes)

Yes you can, though there are some limitations (as FlashBuilder will tell you when you do it), but simple stepping is no problem.

If you have the source code in a project in FlashBuilder, FB should find the associated code automatically. If you don't you can associate the source code to the swc manually. Go to the Flex Build Path window; click on the arrow next to the swc; double click the row that says "Source attachment" and enter the path to the source code.

enter image description here

Can you debug swc in flash builder

Question

Can you debug and step through the code of a swc files in flash builder?

Let's say you even have access to source code (coming from flex library project or flash professional project)! If how?

Thanks

Answer  (has 1 votes)

You should definitely read up on AsyncToken.

Every remote procedure call on a RemoteObject will return one:

var token:AsyncToken = myTableFactory.removeMyTableRow(myTableRow.id);

There are now two things you can do with this token.

Add a Responder

You can add a Responder to each call, which gives you the possibility to have a unique handler for each call:

token.addResponder(new Responder(handleResult, handleFault));

Be sure to remove your global result and fault handlers before trying this. Also I've used the default Responder class here, but any class implementing IResponder will do.

Piggyback your id

You can add new properties to the token since it's a dynamic class. For instance the id may come in handy here:

token.removedId = myTableRow.id;

Or maybe even the entire class:

token.removedRow = myTableRow;

Now you can find these values in the event handlers:

private function handleResult(event:ResultEvent):void {
    trace(event.token.removedId);
}

The same principle applies to FaultEvent

Flex - How to get the parameters passed to a RemoteObject call when a FaultEvent is triggered?

Question

I call a RemoteObject method inside a loop. This method receive a row id as parameter that deletes the row in a database. Inside a loop, lots of calls could be made at once. Some of the calls could fire a FaultEvent. How do I detect the row id that fired the FaultEvent?

The remoteobject:

<mx:RemoteObject id="myTableFactory" destination="myTableFactoryFactory"/>

The loop:

myTableFactory.addEventListener(FaultEvent.FAULT, faultFunction);
for each (var myTableRow:myTable in rowsToBeExcludedArray)
{
  myTableFactory.removeMyTableRow(myTableRow.id);
}

private function faultFunction(e:FaultEvent):void
{
  // The main question. How to get myTableRow.id that fired the FaultEvent
}

Thanks.

Carlos Lima.

Answer  (accepted and has 1 votes)

I think you may be asking the wrong question. As I understand it, you want the x/y position relative to 'page'. You can use the DisplayObject#globalToLocal() function to find this.

Just take the the global coordinates and convert them to local coordinates relative to 'page':

var coordinates:Point = new Point(event.stageX, event.stageY);
coordinates = page.globalToLocal(coordinates);
objX = coordinates.x;
objY = coordinates.y;

Flex Mobile: List flickers

Question

Ok I have a List with an IconItemRenderer in it. When I set it's dataprovider in AS3 and I begin scrolling, the list is flickering one time (gets white for one frame). This only happens when the messageField/messageFunction is set and there is a different number of lines in the message areas. I'm sure this is a framework bug. Has anyone had the same experience? I would be glad if someone knows a workaround for this. Thanks in advance.


Here's an example code for a view component. Strange to say the flickering seems to take sometimes more, sometimes less time. I tested it on Android and in Desktop mode (adl), error occures on both. The "blabla.." is just to get a string with a random number of lines.

<?xml version="1.0" encoding="utf-8"?>
<s:View xmlns:fx="http://ns.adobe.com/mxml/2009"
        xmlns:s="library://ns.adobe.com/flex/spark" title="HomeView">
    <s:actionContent>
        <s:Button label="Set List" click="btn_click(event)"/>
    </s:actionContent>
    <s:List width="100%" height="100%" id="list">
        <s:itemRenderer>
            <fx:Component>
                <s:IconItemRenderer messageField="text"/>
            </fx:Component>
        </s:itemRenderer>
    </s:List>
    <fx:Script>
        <![CDATA[
            import mx.collections.ArrayList;

            protected function btn_click(event:MouseEvent):void
            {
                var al:ArrayList = new ArrayList;
                var obj:Object;
                var str:String = "blablablablablablablablablablablablablablablablablablablablabblablablablablablablablablablablablablablablablablablablablabblablablablablablablablablablablablablablablablablablablablablablablablablablablablablablablablablablablabla";
                for(var i:int = 0; i < 20; i++) {
                    obj = new Object;
                    obj.text = str.substr(0, Math.random()*str.length);
                    al.addItem(obj);
                }
                list.dataProvider = al;
            }

        ]]>
    </fx:Script>
</s:View>

Answer  (accepted and has 1 votes)

The simple answer to your question is that the gap seems to come from the explicit height you give to the first graphic. Simply remove it and the gap will be gone.

The (IMO) better answer is that this code seems a bit convoluted for creating simple graphics.

If you absolutely need the VerticalLayout, you could rewrite that code like this:

<s:Group>
    <s:layout>
        <s:VerticalLayout gap="0" horizontalAlign="center" />
    </s:layout>
    <s:Line height="100">
        <s:stroke>
            <s:SolidColorStroke color="#333333" />
        </s:stroke>
    </s:Line>
    <s:Line width="100">
        <s:stroke>
            <s:SolidColorStroke color="#333333" />
        </s:stroke>
    </s:Line>
</s:Group>

But if you don't really need it for some reason, it can even be reduced to this:

<s:Group>
    <s:Line height="100" horizontalCenter="0">
        <s:stroke>
            <s:SolidColorStroke color="#333333" />
        </s:stroke>
    </s:Line>
    <s:Line width="100" bottom="0">
        <s:stroke>
            <s:SolidColorStroke color="#333333" />
        </s:stroke>
    </s:Line>
</s:Group>

Capturing mouseEevents on a container, bypassing its children

Question

I am building an RIA application using Flex 4.6 that contains a main borderContainer (page) that can contain some other borderContainers (graphic or text elements).

I added an event listener on the page to listen to click events:

page.addEventListener(MouseEvent.CLICK, clickHandler, true);

clickHandler looks like this:

private function clickHandler(event:MouseEvent):void
{
    // Remove event listeners
    page.removeEventListener(MouseEvent.CLICK, clickHandler, true);

    // Get click position
    objX = event.localX;
    objY = event.localY;
}

My problem is that although the event's currentTarget is always the page (normal), the target can either be the page or one of its children, and then localX doesn't give me the position on the page but on the child.

Is there a way to make sure the page is always the target of the event? Something like stopping the capturing phase on the page so it doesn't go deeper?

Thanks in advance for your help

Darrel

Answer  (has 1 votes)

I think I may have a workaround for you. The problem seems to be related to content justification, so I tried to change the default justification by setting a custom layout with contentJustify instead of the default justify:

<s:VerticalLayout gap="0" 
                  horizontalAlign="contentJustify" 
                  requestedMinRowCount="5" />

This fixed the flicker issue for me, but now the List could also scroll sideways, which was also undesired. This I fixed by setting the horizontalScrollPolicy to off. This is the final result:

<s:List width="100%" height="100%" id="list" horizontalScrollPolicy="off">
    <s:itemRenderer>
        <fx:Component>
            <s:IconItemRenderer messageField="text"/>
        </fx:Component>
    </s:itemRenderer>
    <s:layout>
        <s:VerticalLayout gap="0" horizontalAlign="contentJustify" r
                          equestedMinRowCount="5" />
    </s:layout>
</s:List>

You may want to file this bug officially, though I don't exactly know where you'd have to do that now that Flex is moving from Adobe to Apache.

Flex: gap between graphics

Question

I have a group with inside it 2 Graphics, I set the gap in the vertical layout of the group to 0 but there still is a gap of 1 pixel between the 2 graphics. Any idea how to get rid of this?

<?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">
    <s:Group>
        <s:layout>
            <s:VerticalLayout gap="0"/>
        </s:layout>
        <s:Graphic height="100">
            <s:Path data="M 50 0 L 50 100 Z" height="100">
                <s:stroke>
                    <s:SolidColorStroke color="#333333"/>
                </s:stroke>
            </s:Path>
        </s:Graphic>
        <s:Graphic height="1">
            <s:Path data="M 0 0 L 100 0 Z" height="1">
                <s:stroke>
                    <s:SolidColorStroke color="#333333"/>
                </s:stroke>
            </s:Path>
        </s:Graphic>
    </s:Group>
</s:Application>

Answer  (has 0 votes)

You are probably building new functionality with an old SDK. Or perhaps you are reusing a third-party component that was built with a newer SDK inside you application built with an older SDK.

In either event the DesignLayer class was introduced in Flex version 4, as stated in the docs. So if you're building your application with some flavor of Flex 3, it makes sense the DesignLayer class can't be found, simply because it isn't there.

Go have a look in the framework's source code at [sdk-path]\frameworks\projects\framework\src\mx\core. In Flex 4+ you'll find the file DesignLayer.as there. Not so in Flex 3.

Class mx.core::DesignLayer could not be found

Question

I am trying to run my Flex project, however on runtime I get the error: VerifyError: Error #1014: Class mx.core::DesignLayer could not be found

So I have added an import statement for the Design layer class: import mx.core.DesignLayer, and now I get the error on compile: Definition mx.core::DesignLayer could not be found

What is DesignLayer? Why it could not be found even tough I import it?

Thanks.

Answer  (accepted and has 1 votes)

As we've discussed in the comments, there are quite a few things in your code that could be possible sources for misbehaviour. I happened to have a header renderer lying around with very similar functionality that works perfectly. So I'll just dump the code here and you can start working off of that.

Some notes:

.

<s:GridItemRenderer minWidth="21" minHeight="21"
                xmlns:fx="http://ns.adobe.com/mxml/2009" 
                xmlns:s="library://ns.adobe.com/flex/spark" 
                xmlns:vmm="library://ns.vmm.be/flex/components">

<fx:Declarations>
    <fx:Component id="defaultSortIndicator">
        <s:Path data="M 3.5 7.0 L 0.0 0.0 L 7.0 0.0 L 3.5 7.0" implements="spark.components.gridClasses.IGridVisualElement">

            <s:fill>
                <s:RadialGradient rotation="90" focalPointRatio="1">    
                    <s:GradientEntry id="arrowFill1" color="0" alpha="0.6" />
                    <s:GradientEntry id="arrowFill2" color="0" alpha="0.8" />
                </s:RadialGradient>
            </s:fill>
        </s:Path>
    </fx:Component>

    <s:Label id="labelDisplay" verticalCenter="1" left="0" right="0" top="0" bottom="0"
             textAlign="start" verticalAlign="middle" maxDisplayedLines="1" showTruncationTip="true"
             color.normal="0x555555" color="0x90a938" fontWeight="bold" />
</fx:Declarations>

<fx:Script>
    <![CDATA[
        import spark.components.gridClasses.IGridVisualElement;
        import mx.core.IVisualElement;

        import spark.components.DataGrid;
        import spark.components.GridColumnHeaderGroup;
        import spark.components.gridClasses.GridColumn;
        import spark.primitives.supportClasses.GraphicElement;


        private function dispatchChangeEvent(type:String):void {
            if (hasEventListener(type)) dispatchEvent(new Event(type));
        }            

        //----------------------------------
        //  maxDisplayedLines
        //----------------------------------

        private var _maxDisplayedLines:int = 1;

        [Bindable("maxDisplayedLinesChanged")]
        [Inspectable(minValue="-1")]
        public function get maxDisplayedLines():int {
            return _maxDisplayedLines;
        }

        public function set maxDisplayedLines(value:int):void {
            if (value == _maxDisplayedLines) return;

            _maxDisplayedLines = value;
            if (labelDisplay) labelDisplay.maxDisplayedLines = value;

            invalidateSize();
            invalidateDisplayList();

            dispatchChangeEvent("maxDisplayedLinesChanged");
        }

        //----------------------------------
        //  sortIndicator
        //----------------------------------

        private var _sortIndicator:IFactory;
        private var sortIndicatorInstance:IVisualElement;

        [Bindable("sortIndicatorChanged")]
        public function get sortIndicator():IFactory {
            return (_sortIndicator) ? _sortIndicator : defaultSortIndicator;
        }

        public function set sortIndicator(value:IFactory):void {
            if (_sortIndicator == value) return;

            _sortIndicator = value;
            if (sortIndicatorInstance) {
                sortIndicatorGroup.includeInLayout = false;
                sortIndicatorGroup.removeElement(sortIndicatorInstance);
                sortIndicatorInstance = null;
            }

            invalidateDisplayList();
            dispatchChangeEvent("sortIndicatorChanged");
        }

        override public function prepare(hasBeenRecycled:Boolean):void {
            super.prepare(hasBeenRecycled);

            if (labelDisplay && labelDisplayGroup && (labelDisplay.parent != labelDisplayGroup)) {
                labelDisplayGroup.removeAllElements();
                labelDisplayGroup.addElement(labelDisplay);
            }

            const column:GridColumn = this.column;
            if (sortIndicator && column && column.grid && column.grid.dataGrid && column.grid.dataGrid.columnHeaderGroup) {
                const dataGrid:DataGrid = column.grid.dataGrid;
                const columnHeaderGroup:GridColumnHeaderGroup = dataGrid.columnHeaderGroup;

                if (columnHeaderGroup.isSortIndicatorVisible(column.columnIndex)) {
                    if (!sortIndicatorInstance) {
                        sortIndicatorInstance = sortIndicator.newInstance();
                        sortIndicatorGroup.addElement(sortIndicatorInstance);
                        invalidateDisplayList();
                    }

                    // Initialize sortIndicator
                    sortIndicatorInstance.visible = true;
                    const gridVisualElement:IGridVisualElement = sortIndicatorInstance as IGridVisualElement;
                    if (gridVisualElement)
                        gridVisualElement.prepareGridVisualElement(column.grid, -1, column.columnIndex);

                    sortIndicatorGroup.includeInLayout = true;
                    sortIndicatorGroup.scaleY = (column.sortDescending) ? 1 : -1;
                }
                else if (sortIndicatorInstance) {
                    sortIndicatorGroup.removeElement(sortIndicatorInstance);
                    sortIndicatorGroup.includeInLayout = false;
                    sortIndicatorInstance = null;
                }
            }
        }

        override public function styleChanged(styleProp:String):void {
            var allStyles:Boolean = !styleProp || styleProp == "styleName";
            super.styleChanged(styleProp);
            if (allStyles) invalidateDisplayList();
        }
    ]]>
</fx:Script>

<s:states>
    <s:State name="normal" />
    <s:State name="hovered" />
    <s:State name="down" />
</s:states>      

<s:Rect id="fill" left="0" right="0" top="0" bottom="0">
    <s:fill>
        <s:LinearGradient rotation="90">
            <s:GradientEntry color.normal="0xf9f9f9" color.hovered="0xfcfdfa" 
                             color.down="0xdceac2" alpha="0.85" />
            <s:GradientEntry color.normal="0xeaeaea" color.hovered="0xdceac2"
                             color.down="0xd2e1b5" alpha="0.85" />
        </s:LinearGradient>
    </s:fill>
</s:Rect>

<s:VGroup left="7" right="7" top="5" bottom="5" gap="6" verticalAlign="middle">
    <s:TextInput width="100%" />
    <s:HGroup width="100%">
        <s:Group id="labelDisplayGroup" width="100%" />
        <s:Group id="sortIndicatorGroup" includeInLayout="false" />
    </s:HGroup>
</s:VGroup>

</s:GridItemRenderer>

How to add a working s:TextInput to a s:Datagrid HeaderRenderer?

Question

I need/want to add a s:TextInput to the headers of some of my datagrids to provide filtering functionality for the tables (the idea is: "type text in inputfield, hit enter, datagrid gets filtered"). For now I'm working on a HeaderRenderer using a s:TextInput, but there will also be Renderers using s:CheckBoxes and s:DropDownLists.

I'm trying to do this with a custom RendererSkin, but I'm running into several issues:

  1. You can't type in the s:TextInput (although the cursor changes to the I-Beam on mouseover and the control get the focus border).
  2. After interacting a few times with the headers, the s:TextInputs seem to "leak" some kind of white rectangle (see screenshot).
  3. verticalAlign="bottom" doesn't seem to work the way I assumed it would work.

So far my HeaderRenderer looks like this:

<?xml version="1.0" encoding="utf-8"?>
<s:DefaultGridHeaderRenderer xmlns:fx="http://ns.adobe.com/mxml/2009" xmlns:s="library://ns.adobe.com/flex/spark" xmlns:mx="library://ns.adobe.com/flex/mx"
    mouseEnabledWhereTransparent="true">
    <fx:Script>
        <![CDATA[
            import spark.components.DataGrid;
            import spark.components.GridColumnHeaderGroup;
            import spark.components.TextInput;
            import spark.components.gridClasses.GridColumn;
            import spark.components.gridClasses.IGridVisualElement;
            import spark.primitives.supportClasses.GraphicElement;

            import mx.collections.ArrayCollection;
            import mx.core.IFactory;
            import mx.core.IVisualElement;
            import mx.events.FlexEvent;

            // chrome color constants and variables
            private static const DEFAULT_COLOR_VALUE:uint = 0xCC;

            private static const DEFAULT_COLOR:uint = 0xCCCCCC;

            private static const DEFAULT_SYMBOL_COLOR:uint = 0x000000;

            private static var colorTransform:ColorTransform = new ColorTransform();

            private function dispatchChangeEvent(type:String):void {
                if (hasEventListener(type))
                    dispatchEvent(new Event(type));
            }

            // ----------------------------------
            // maxDisplayedLines
            // ----------------------------------
            private var _maxDisplayedLines:int = 1;

            [Bindable("maxDisplayedLinesChanged")]
            [Inspectable(minValue="-1")]
            override public function get maxDisplayedLines():int {
                return _maxDisplayedLines;
            }

            /**
             *  @private
             */
            override public function set maxDisplayedLines(value:int):void {
                if (value == _maxDisplayedLines)
                    return;

                _maxDisplayedLines = value;
                if (labelDisplay)
                    labelDisplay.maxDisplayedLines = value;

                invalidateSize();
                invalidateDisplayList();

                dispatchChangeEvent("maxDisplayedLinesChanged");
            }

            // ----------------------------------
            // sortIndicator
            // ----------------------------------
            private var _sortIndicator:IFactory;

            private var sortIndicatorInstance:IVisualElement;

            [Bindable("sortIndicatorChanged")]
            override public function get sortIndicator():IFactory {
                return (_sortIndicator) ? _sortIndicator : defaultSortIndicator;
            }

            override public function set sortIndicator(value:IFactory):void {
                if (_sortIndicator == value)
                    return;

                _sortIndicator = value;
                if (sortIndicatorInstance) {
                    sortIndicatorGroup.includeInLayout = false;
                    sortIndicatorGroup.removeElement(sortIndicatorInstance);
                    sortIndicatorInstance = null;
                }

                invalidateDisplayList();
                dispatchChangeEvent("sortIndicatorChanged");
            }

            override public function prepare(hasBeenRecycled:Boolean):void {
                super.prepare(hasBeenRecycled);

                if (labelDisplay && labelDisplayGroup && (labelDisplay.parent != labelDisplayGroup)) {
                    labelDisplayGroup.removeAllElements();
                    labelDisplayGroup.addElement(labelDisplay);
                }

                if (labelDisplayGroup.numChildren < 2) {
                    var filter:TextInput = new TextInput();
                    filter.percentWidth = 100;
                    filter.addEventListener(FlexEvent.ENTER, filter_handleEnter);
                    filterDisplayGroup.addElement(filter);
                }

                const column:GridColumn = this.column;
                if (sortIndicator && column && column.grid && column.grid.dataGrid && column.grid.dataGrid.columnHeaderGroup) {
                    const dataGrid:DataGrid = column.grid.dataGrid;
                    const columnHeaderGroup:GridColumnHeaderGroup = dataGrid.columnHeaderGroup;

                    if (columnHeaderGroup.isSortIndicatorVisible(column.columnIndex)) {
                        if (!sortIndicatorInstance) {
                            sortIndicatorInstance = sortIndicator.newInstance();
                            sortIndicatorGroup.addElement(sortIndicatorInstance);
                            chromeColorChanged = true;
                            invalidateDisplayList();
                        }

                        // Initialize sortIndicator
                        sortIndicatorInstance.visible = true;
                        const gridVisualElement:IGridVisualElement = sortIndicatorInstance as IGridVisualElement;
                        if (gridVisualElement)
                            gridVisualElement.prepareGridVisualElement(column.grid, -1, column.columnIndex);

                        sortIndicatorGroup.includeInLayout = true;
                        sortIndicatorGroup.scaleY = (column.sortDescending) ? 1 : -1;
                    } else {
                        if (sortIndicatorInstance) {
                            sortIndicatorGroup.removeElement(sortIndicatorInstance);
                            sortIndicatorGroup.includeInLayout = false;
                            sortIndicatorInstance = null;
                        }
                    }
                }
            }

            private var chromeColorChanged:Boolean = false;

            private var colorized:Boolean = false;

            override protected function updateDisplayList(unscaledWidth:Number, unscaledHeight:Number):void {
                // Apply chrome color
                if (chromeColorChanged) {
                    var chromeColor:uint = getStyle("chromeColor");

                    if (chromeColor != DEFAULT_COLOR || colorized) {
                        colorTransform.redOffset = ((chromeColor & (0xFF << 16)) >> 16) - DEFAULT_COLOR_VALUE;
                        colorTransform.greenOffset = ((chromeColor & (0xFF << 8)) >> 8) - DEFAULT_COLOR_VALUE;
                        colorTransform.blueOffset = (chromeColor & 0xFF) - DEFAULT_COLOR_VALUE;
                        colorTransform.alphaMultiplier = alpha;

                        transform.colorTransform = colorTransform;

                        var exclusions:Array = [labelDisplay, sortIndicatorInstance];

                        // Apply inverse colorizing to exclusions
                        if (exclusions && exclusions.length > 0) {
                            colorTransform.redOffset = -colorTransform.redOffset;
                            colorTransform.greenOffset = -colorTransform.greenOffset;
                            colorTransform.blueOffset = -colorTransform.blueOffset;

                            for (var i:int = 0; i < exclusions.length; i++) {
                                var exclusionObject:Object = exclusions[i];

                                if (exclusionObject && (exclusionObject is DisplayObject || exclusionObject is GraphicElement)) {
                                    colorTransform.alphaMultiplier = exclusionObject.alpha;
                                    exclusionObject.transform.colorTransform = colorTransform;
                                }
                            }
                        }

                        colorized = true;
                    }

                    chromeColorChanged = false;
                }

                super.updateDisplayList(unscaledWidth, unscaledHeight);
            }

            override public function styleChanged(styleProp:String):void {
                var allStyles:Boolean = !styleProp || styleProp == "styleName";

                super.styleChanged(styleProp);

                if (allStyles || styleProp == "chromeColor") {
                    chromeColorChanged = true;
                    invalidateDisplayList();
                }
            }

            private function filter_handleEnter(event:FlexEvent):void {
                if (this.grid.dataProvider is ArrayCollection) {
                    (this.grid.dataProvider as ArrayCollection).refresh();
                }
            }
        ]]>
    </fx:Script>

    <fx:Declarations>
        <fx:Component id="defaultSortIndicator">
            <s:Path data="M 3.5 7.0 L 0.0 0.0 L 7.0 0.0 L 3.5 7.0" implements="spark.components.gridClasses.IGridVisualElement">
                <fx:Script>
                    <![CDATA[
                        import spark.components.DataGrid;
                        import spark.components.Grid;

                        public function prepareGridVisualElement(grid:Grid, rowIndex:int, columnIndex:int):void {
                            const dataGrid:DataGrid = grid.dataGrid;
                            if (!dataGrid)
                                return;

                            const color:uint = dataGrid.getStyle("symbolColor");
                            arrowFill1.color = color;
                            arrowFill2.color = color;
                        }
                    ]]>
                </fx:Script>

                <s:fill>
                    <s:RadialGradient rotation="90" focalPointRatio="1">
                        <s:GradientEntry id="arrowFill1" color="0" alpha="0.6"/>

                        <s:GradientEntry id="arrowFill2" color="0" alpha="0.8"/>
                    </s:RadialGradient>
                </s:fill>
            </s:Path>
        </fx:Component>

        <s:Label id="labelDisplay" verticalCenter="1" left="0" right="0" top="0" bottom="0" textAlign="start"
            fontWeight="bold" verticalAlign="bottom" maxDisplayedLines="1" showTruncationTip="true"/>
    </fx:Declarations>

    <s:states>
        <s:State name="normal"/>
        <s:State name="hovered"/>
        <s:State name="down"/>
    </s:states>

    <!-- layer 1: shadow -->

    <s:Rect id="shadow" left="-1" right="-1" top="-1" bottom="-1" radiusX="2">
        <s:fill>
            <s:LinearGradient rotation="90">
                <s:GradientEntry color="0x000000" color.down="0xFFFFFF" alpha="0.01" alpha.down="0"/>

                <s:GradientEntry color="0x000000" color.down="0xFFFFFF" alpha="0.07" alpha.down="0.5"/>
            </s:LinearGradient>
        </s:fill>
    </s:Rect>

    <!-- layer 2: fill -->

    <s:Rect id="fill" left="0" right="0" top="0" bottom="0">
        <s:fill>
            <s:LinearGradient rotation="90">
                <s:GradientEntry color="0xFFFFFF" color.hovered="0xBBBDBD" color.down="0xAAAAAA" alpha="0.85"/>

                <s:GradientEntry color="0xD8D8D8" color.hovered="0x9FA0A1" color.down="0x929496" alpha="0.85"/>
            </s:LinearGradient>
        </s:fill>
    </s:Rect>

    <!-- layer 3: fill lowlight -->

    <s:Rect id="lowlight" left="0" right="0" top="0" bottom="0">
        <s:fill>
            <s:LinearGradient rotation="270">
                <s:GradientEntry color="0x000000" ratio="0.0" alpha="0.0627"/>

                <s:GradientEntry color="0x000000" ratio="0.48" alpha="0.0099"/>

                <s:GradientEntry color="0x000000" ratio="0.48001" alpha="0"/>
            </s:LinearGradient>
        </s:fill>
    </s:Rect>

    <!-- layer 4: fill highlight -->

    <s:Rect id="highlight" left="0" right="0" top="0" bottom="0">
        <s:fill>
            <s:LinearGradient rotation="90">
                <s:GradientEntry color="0xFFFFFF" ratio="0.0" alpha="0.33" alpha.hovered="0.22" alpha.down="0.12"/>

                <s:GradientEntry color="0xFFFFFF" ratio="0.48" alpha="0.33" alpha.hovered="0.22" alpha.down="0.12"/>

                <s:GradientEntry color="0xFFFFFF" ratio="0.48001" alpha="0"/>
            </s:LinearGradient>
        </s:fill>
    </s:Rect>

    <!-- layer 5: highlight stroke (all states except down) -->

    <s:Rect id="highlightStroke" left="0" right="0" top="0" bottom="0" excludeFrom="down">
        <s:stroke>
            <s:LinearGradientStroke rotation="90" weight="1">
                <s:GradientEntry color="0xFFFFFF" alpha.hovered="0.22"/>

                <s:GradientEntry color="0xD8D8D8" alpha.hovered="0.22"/>
            </s:LinearGradientStroke>
        </s:stroke>
    </s:Rect>

    <!-- layer 6: highlight stroke (down state only) -->

    <s:Rect id="hldownstroke1" left="0" right="0" top="0" bottom="0" includeIn="down">
        <s:stroke>
            <s:LinearGradientStroke rotation="90" weight="1">
                <s:GradientEntry color="0x000000" alpha="0.25" ratio="0.0"/>

                <s:GradientEntry color="0x000000" alpha="0.25" ratio="0.001"/>

                <s:GradientEntry color="0x000000" alpha="0.07" ratio="0.0011"/>

                <s:GradientEntry color="0x000000" alpha="0.07" ratio="0.965"/>

                <s:GradientEntry color="0x000000" alpha="0.00" ratio="0.9651"/>
            </s:LinearGradientStroke>
        </s:stroke>
    </s:Rect>

    <s:Rect id="hldownstroke2" left="1" right="1" top="1" bottom="1" includeIn="down">
        <s:stroke>
            <s:LinearGradientStroke rotation="90" weight="1">
                <s:GradientEntry color="0x000000" alpha="0.09" ratio="0.0"/>

                <s:GradientEntry color="0x000000" alpha="0.00" ratio="0.0001"/>
            </s:LinearGradientStroke>
        </s:stroke>
    </s:Rect>

    <s:VGroup bottom="5" left="7" right="7" top="5" gap="2" verticalAlign="bottom">
        <s:Group id="filterDisplayGroup" width="100%"/>

        <s:HGroup bottom="5" left="7" right="7" top="5" gap="2" verticalAlign="bottom">
            <s:Group id="labelDisplayGroup" width="100%" left="8" right="8"/>

            <s:Group id="sortIndicatorGroup" includeInLayout="false"/>
        </s:HGroup>
    </s:VGroup>
</s:DefaultGridHeaderRenderer>

So basically, what I want is this (basically a much simpler form of this $800 datagrid component):

enter image description here

What I currently have is this (with the above mentioned problems):

enter image description here enter image description here


Can anyone give me a hint what's going wrong with my Renderer (primarily why the freck I can't type in the inputfield and where this white thing does come from)?

Answer  (has 1 votes)

Of course I do not know your concrete case, but in general I would agree with your colleagues. Especially if you wouldn't like to provide helpdesk services for your users 24/7. Performance may indeed be an issue if your users don't have powerful machines. I know Jetty is pretty lightweight, but on some older computers, you want to have as few processes running at the same time as you can.

But what I would be more concerned about, is the maintainability of your application. For starters, you'll have to get the whole stack installed on the users machines, which won't be easy. Once you've got that covered, you have that many more points of failure. Your application can now fail in the AIR app, in the local server, in the database or in the connection between one of those layers.

If you think the server you'll deploy on the local machines will behave a 100% in the same way your current web server does, you're probably wrong. You're not running Jetty or an embedded DB online, are you? Your users may have all kinds of different operating systems which you have to account for.

How are you going to push updates to your application? This is a pretty simple procedure in an AIR app, but it's going to be a lot harder if you have to also update the local server-side code.

I reckon in the long run it'll pay off rewriting some logic inside your AIR app. It will cost you some up front, but it'll cost you less in maintenance. I also don't think that the complete model should be rewritten. With these kinds of online/offline problems you can develop a strategy where you synchronize only the most important data. And if you dislike the code duplication, you can always write a generator that can take your Java model and create ActionScript duplicates.

Spring/Flex(online) to Spring/Air(offline)

Question

I've been working on a project that uses Flex + Blazeds + Spring. Now some parts of it must run offline due to connectivity issues. The problem is how to deal with the existing architecture, preserving it as much as possible, or at least how to create a solution not too much hard to evolve. I've seen many similar questions searching on the internet, but the most common approach is writing all code in actionscript(including business logic, access to database, transactions and so on), what I particularly don't consider suitable for the case. I'm thinking of using Jetty embedded in the application and some kind of embeddable database such as Java DB, so I could access my Spring services normally without any big change. Some workmates, however, disagree. They think that a web server running on a client's machine can lead to performance issues and a more lightweight solution is the way to go. Until now, no other solution came up. What do you suggest?

Answer  (accepted and has 1 votes)

Use the GridSelectionEvent.SELECTION_CHANGE event instead for two reasons:

.

<s:DataGrid id="dg" selectionChange="onSelectionChange(event)" />

private function onSelectionChange(event:GridSelectionEvent):void {
    var index:int = event.selectionChange.rowIndex;
    var patient = dg.dataProvider.getItemAt(index);
    patientSelect(patient);
}

How to tell if the mouse cursor is over a component using the mouse coordinates?

Question

I'm trying to determine with the help of a mouse event if I'm over a specific component.

So right now I have two components, let's say buttonA and buttonB. ButtonA has a listener on it already listening for the mouse out event. ButtonB is flush against the edge of ButtonA.

I need to find out the code for it. Here is more details:

        protected function _mouseOutHandler(event:MouseEvent):void
        {
            if (data.subCategories.length>0)
            {
                if (MOUSE IS NOT OVER BUTTONB) {

                }

                if (MOUSE IS OVER DROPDOWNB) {

                }
            }
        }

Answer  (accepted and has 1 votes)

That doesn't look like a very good tutorial you're following there (in my opinion). In that code, you have one event listener for all the statements that are being executed. It even has just one SQLStatement that executes different queries. I don't know exactly what is going wrong with your code, but I'm fairly certain the cause is to be found there. (And don't even get me started about that Timer used as a delay when a statement is still executing. Yuck!). I strongly suggest you look for a better source for learning Flex/AIR/SQLite.

You should simply create a new SQLStatement, or at least discrete event handlers for each Statement execution. A better way to do this, would be to use the Responder class, like this:

var stmt:SQLStatement = new SQLStatement();
stmt.sqlConnection = connection;
stmt.text = query;

var token:Responder = new Responder(onResult, onFail);
stmt.execute(-1, token);

The SQLConnection can be shared though, if you don't mind keeping the connection to your database open all the time.

Flex: use the selectedItem of DateGrid in an function

Question

I'm using a spark Datagrid in an mobile Flex (4.6) application. When a row is selected in the grid I want to trigger a function and use the content of the selected item in that same function. This is my Datagrid

<s:DataGrid id="patientGrid" x="317" y="211" width="393" height="177"
            dataProvider="{patientInfo}" gridClick="patientSelect(event)">
    <s:columns>
        <s:ArrayList>
            <s:GridColumn dataField="FirstName" headerText="First Name"/>
            <s:GridColumn dataField="LastName" headerText="Last Name"/>
            <s:GridColumn dataField="DateOfBirth" headerText="Date Of Birth"/>
            <s:GridColumn dataField="Gender" headerText="Gender"/>
        </s:ArrayList>
    </s:columns>
</s:DataGrid>

And when a item is selected the patientselected funtion needs the ability to work with the content of that selected item.

I hope my question is clear, and thanks for helping!

Answer  (accepted and has 1 votes)

Just use a class selector for the specific List, like this:

.myList s|VScrollBar {
    skinClass: ClassReference("net.riastar.skin.VScrollBarSkin");
}

<s:List styleName="myList" />

Adobe Air: why SQLStatement's getResult().data is null?

Question

Using Flash Builder 4.6, I am following http://www.flex-blog.com/adobe-air-sqlite-example/ as an example, and there is one part of codes that does not work:

private function resault(e:SQLEvent):void
{
    // with sqls.getResault().data we get the array of objects for each row out of our database
    var data:Array = sqls.getResult().data;
    // we pass the array of objects to our data provider to fill the datagrid
    dp = new ArrayCollection(data);
}

Checking the program during runtime gives me that sqls.getResult() returns a valid SQLResult object, but its data is null.

And from my previous question Adobe Air: convert sqlite's result [object Object] to String?, it seems I am asking the wrong question.

Nevertheless, I've checked my SQLResult object with

trace(ObjectUtil.toString(sqls.getResult()));

and I can see that I got all of my content from sqlite:

(flash.data::SQLResult)#0
  complete = true
  data = (Array)#1
    [0] (Object)#2
      first_name = "AAA"
      id = 1
      last_name = "BBB"
    [1] (Object)#3
      first_name = "AAA"
      id = 2
      last_name = "BBB"
    [2] (Object)#4
      first_name = "qqq"
      id = 3
      last_name = "qqq"
  lastInsertRowID = 0
  rowsAffected = 0

So what's going on here? Do I really have to create my own function to parse all of my sqlite elements and then place them in the data provider myself? Yes, I can do that, but seriously, many tutorials have shown using:

var data:Array = sqls.getResult().data;
dp = new ArrayCollection(data);

Now, back on the question: What might be the possible causes of sqls.getResult().data becoming null?

Answer  (accepted and has 2 votes)

You'll have to create a custom skin. Now, HSlider is a little bit special in that it has some subcomponents that are also skinnable. You'll actually have to create three custom skins:

The track and the thumb are both in fact Buttons so those skins will have to be Button skins.

Explaining the entire process will make this answer too lengthy and specific, so I'll just get you started. You should be able to figure it out from there. I'll also assume you're using FlashBuilder as an IDE.

Create main skin

Set the skinClass style on an HSlider and hit Alt+Space. This will bring up code completion, but you can also select "Create Skin...".

enter image description here

Select that and a wizard will appear. Fill out something like the following. Note that we're making a copy of the default Spark HSlider skin. We remove the styling code because it will not be necessary in such a customized skin.

enter image description here

Create track and thumb skins

Open this new skin class and scroll down to the bottom. You'll see two Buttons; one with id track and one with id thumb. Their skinClass style is set to the default spark skins for these buttons. Delete the content and repeat the operation of the previous step (creating a new skin), only this time create a copy of HSliderTrackSkin and HSliderThumbSkin

Edit the skins

You now have an exact copy of the default Spark skins for HSlider (except you removed the styling). Now you can start editing: changing colors, changing shapes, etc. If you need more information about Flex graphics, I suggest you Google up on FXG. But you can just try to fiddle with the default skins and see where you can get too.

How do you set the scroll bar skin on a single List instance?

Question

I've created a scrollbar skin that I'm able to apply to all List components using the following CSS:

<fx:Style>
    @namespace s "library://ns.adobe.com/flex/spark";

    s|List s|HScrollBar {
        skinClass: ClassReference("com.skins.myScroller.MyHorizontalScrollerSkin");
        fixedThumbSize:true;
    }

</fx:Style>

The design has changed and now I need to apply this skin to only one List instance. How do I do this (preferring CSS or inline if possible)?

Answer  (has 4 votes)

Because you're using a for each loop. Use a for loop instead:

for (var key:* in spellBook) {
    trace(key + ': ' + spellBook[key]);
}

How to customise a HSlider in flex?

Question

I'm new to flex,and I want to change the image of HSlider,like this

enter image description here

What should I do?please give me a simple example.

Answer  (accepted and has 0 votes)

You're creating an ArrayList with one item a 100 times. Replace with this and you should be fine:

var arr:ArrayList = new ArrayList();
for (var i:int = 0; i<100; i++) {
    arr.addItem(i);
} 

Or better yet, just wrap your XML in an XMLListCollection instead of copying the nodes one by one (assuming it is the actual content of the XML data you want instead of the indices):

private function completeHandler(event:Event):void
{
    var xmlData:XML = XML(event.target.data);
    list.dataProvider = new XMLListCollection(xmlData.children());
}

(Note that this is not DataBinding: it is just setting the dataProvider property)

DataBinding in List

Question

I am trying to bind data within a ArrayList to a list, but here only the last element shows up on the list(99), not the entire contents of the arraylist.

private function completeHandler(event:Event):void
        {
            var xmlData:XML = XML(event.target.data);
            trace(xmlData);
             var i:int = 0;
            for (i;i<100;i++)
            {
                var arr:ArrayList = new ArrayList();
                arr.addItem(i);
                trace(arr);
            } 
            list.dataProvider = arr;
        }

I am not able to figure out what to do here?

Answer  (has 1 votes)

Spark components inheriting from ListBase no longer dispatch ItemClick events. You can use the IndexChangeEvent event instead though. It has a property newIndex that tells you which is the newly selected item (or tab in this particular case).

<s:TabBar dataProvider="{dp}" change="trace('selected: ' + event.newIndex)" />

One big difference with the old ItemClick is that this event is only dispatched when the selected item actually changes (as opposed to whenever it is clicked). If you really want the behaviour of ItemClick back, you can create a custom ItemRenderer that dispatches an ItemClick event.


If you want to react on every click there are a few approaches. Here are two of them:

1./ Create a custom ItemRenderer that dispatches an ItemClick event.

.

public class TabBarButton extends ButtonBarButton {

    override public function initialize():void {
        super.initialize();
        addEventListener(MouseEvent.CLICK, fireItemClick);
    }

    private function fireItemClick(event:MouseEvent):void {
        owner.dispatchEvent(new ItemClickEvent(
            ItemClickEvent.ITEM_CLICK, false, false, null, itemIndex, null, data
        ))
    }

}

You can now use it like this:

<s:TabBar id="tabBar" dataProvider="{dp}" 
          itemRenderer="net.riastar.TabBarButton" />

tabBar.addEventListener(ItemClickEvent.ITEM_CLICK, onItemClick);

2./ Another approach would be to just listen for any click event on the TabBar and use event.target to find the clicked tab:

<s:TabBar dataProvider="{dp}" click="trace(event.target)" />
//traces tabBar.TabBarSkin1.dataGroup.TabBarButton1

Note that this is a direct answer to your question, but I actually don't think you should do this. In most cases IndexChangeEvent.CHANGE will do just fine.

Why does iterating over a generic object in ActionScript give me values instead of keys?

Question

I may be doing something really stupid, but I don't get why the below code doesn't work...

Here, I create a generic Object called spellbook:

// A list of all the player's spells
public var spellBook:Object = {};

Here, I add a key-value pair to the spellbook:

spellBook["bubble"] = new BubbleSpell(spellBook);

And here I try to output the contents of the spellbook:

trace("Spells initialised.  Available spells are:");
for each (var _spell:String in spellBook)
{
    trace("  ", _spell, " : ", spellBook[_spell]);
}

But this is the output I get:

Spells initialised.  Available spells are:
   [object BubbleSpell]  :  undefined

What I don't get is why it's not outputting:

Spells initialised.  Available spells are:
   bubble : [object BubbleSpell]

??

It's as if I'm iterating over the values in spellbook, rather than the keys... is that what's happening? All the docs I've seen so far seem to indicate that this is the correct way to iterate over a dictionary (which a generic object kind of is...) Do I need to call a method to get keys instead of values for generic objects?

So confused!

Answer  (accepted and has 2 votes)

Short answer

Use the backgroundColor style instead of the opaqueBackground property.

Long answer

If you replace that container.opaqueBackground = backColor with container.setStyle("backgroundColor", backColor) (just as you did with the Labels) the red and green zones are right where you would expect them to be.

Bear in mind that opaqueBackground is a pure AS3 property of the DisplayObject class. It has nothing to do (directly) with the Flex framework. So what you see, is those DisplayObjects somewhat overlapping, but not the Flex SkinnableContainers.

To be more precise: the SkinnableContainers extend from DisplayObject, so technically they are overlapping, but their graphics and contents are aligned in such a way that visually (and in any other practical way except the usage of opaqueBackground) they are not.

itemclick event in spark tabbar?

Question

Hallo tabbar supports item click event. However spark tabBar doesnot supports itemClick event.

is there way to listen itemclick event in SPARK TABBAR

thanks all

Answer  (accepted and has 1 votes)

The answer to that question is actually fairly short: it's an architectural decision made by the Flex SDK engineers. If you take a look at the Flex source code, you'll see a try ... catch block swallowing most errors thrown in a Binding.

Pro: makes it easier to use bindings, since you don't have to account for all possible faulty states

Con: it can be harder to debug (though if you know this can happen and you have good unit tests, you can reduce frustration from that side to nearly zero)


The source code I was talking about can be found in mx.binding.Binding (in the 'framework' project) in method wrapFunctionCall(). Here's the relevant part:

    try {
       ...
    }
    catch(error:Error)
    {
        // Certain errors are normal when executing a srcFunc or destFunc,
        // so we swallow them:
        //   Error #1006: Call attempted on an object that is not a function.
        //   Error #1009: null has no properties.
        //   Error #1010: undefined has no properties.
        //   Error #1055: - has no properties.
        //   Error #1069: Property - not found on - and there is no default value
        // We allow any other errors to be thrown.
        if ((error.errorID != 1006) &&
            (error.errorID != 1009) &&
            (error.errorID != 1010) &&
            (error.errorID != 1055) &&
            (error.errorID != 1069))
        {
            throw error;
        }
        else
        {
            if (BindingManager.debugDestinationStrings[destString])
            {
                trace("Binding: destString = " + destString + ", error = " + error);
            }
        }
    }

Flex container grows too much, overlapping other elements

Question

Here's the thing. I'm using pure AS3 to do some special automatic layout of some Flex components, when I discover that some SkinnableContainers grow bigger than their content, even if they have 0 padding and the layout inside them is BasicLayout (i.e. "full-manual" layout).

Here's a screenshot and the code. This little test creates an Application and sets the layout to HorizontalLayout. Then, inside the Application container, I create two SkinnableContainers, each containing a Label with some text. I set the SkinnableContainers to have maximum 150px width, and the Labels inside them to have 100% width of their parents.

Screenshot

Layout screenshot

Main.mxml

<?xml version="1.0" encoding="utf-8"?>
<local:MainApplication xmlns:fx="http://ns.adobe.com/mxml/2009" xmlns:local="*"/>

MainApplication.as

package {
  import flash.events.Event;
  import spark.components.Application;
  import spark.components.SkinnableContainer;
  import spark.components.Label;
  import spark.layouts.HorizontalLayout;
  import spark.layouts.BasicLayout;

  public class MainApplication extends Application {
    public function MainApplication() {
      super();

      var hl : HorizontalLayout = new HorizontalLayout();
      hl.gap = 0;
      hl.paddingTop = 0;
      hl.paddingLeft = 0;
      hl.paddingRight = 0;
      hl.paddingBottom = 0;

      this.layout = hl;

      var leftBlock : SkinnableContainer = myNewContainer(0xFF0000);
      var rightBlock : SkinnableContainer = myNewContainer(0x00FF00);;
      var leftLabel : Label = myNewLabel("oranges blackberries bananas kiwis plums apples");
      var rightLabel : Label = myNewLabel("apricots peaches lemons pineapples");

      leftBlock.addElement(leftLabel);
      rightBlock.addElement(rightLabel);

      this.addElement(leftBlock);
      this.addElement(rightBlock);
    }

    private function myNewContainer(backColor : Number) : SkinnableContainer {
      var container : SkinnableContainer = new SkinnableContainer();
      container.layout = new BasicLayout();
      container.maxWidth = 150;
      container.explicitWidth = 150;
      container.opaqueBackground = backColor;
      return container;
    }

    private function myNewLabel(text : String) : Label {
      var myLabel : Label = new Label();
      myLabel.text = text;
      myLabel.percentWidth = 100;
      myLabel.setStyle("color", 0xFFFFFF);
      myLabel.setStyle("backgroundColor", 0x000000);
      return myLabel;
    }
  }
}

It looks to me like the SkinnableContainers (red and green backgrounds) don't care about the maxWidth = 150; I applied to them, but the Labels (white text on black background) respect this. I was expecting to see only the Labels, without any overextended red or green backgrounds. Is there some padding involved? Am I missing anything?

Answer  (accepted and has 1 votes)

You can find a very similar question with my answer here: Which is the best way to get Data in my Flex Application?.

However this question deals more with the performance aspect so I'll elaborate. Basically you should just pick whichever language you're most efficient with. Note that besides Java, ColdFusion and PHP, that could also be Ruby, Python, .NET and probably more, as long as it has an implementation of AMF (de)serialization.

If there's one of these languages you know best, pick that. If not, go for ColdFusion or Java since I believe they're the easiest to setup for communication with Flex. And for the choice between those two:

Why does MXML data binding swallow TypeErrors?

Question

The following code shoud throw an Error #1009: Cannot access a property or method of a null object reference:

var label:Label;
label.text = value;

However, it doesn't if it's inside of a setter which is set by MXML data binding:

public function set buggySetter(value:String):void {
    var label:Label;
    label.text = value; //will fail silently
}

To reproduce this weird behaviour, first, create a simple custom component by extending s:Label:

package {
    import spark.components.Label;

    public class BuggyLabel extends Label {
        public function set buggySetter(value:String):void {
            var label:Label;
            label.text = value; //will fail silently
        }
    }
}

Sectond, add BuggyLabel to an Application and bind buggySetter:

<fx:Script>
    <![CDATA[
        [Bindable]
        public var foo:String = 'NULL has no properties';
    ]]>
</fx:Script>

<local:BuggyLabel buggySetter="{foo}"/>

Why does this app fail silently?

Answer  (accepted and has 0 votes)

Apparently embedded assets are not by default serialized to ByteArray as I suggested in the comments. For example an image is serialized into a BitmapAsset class.

[Embed(source="sourceImg.png")]
private var MyImage:Class;

For this embed you could do:

var bmp:BitmapAsset = new MyImage();

There are techniques to convert that BitmapAsset into a ByteArray, but there's also an easier way: if you set the type to 'octetstream' in the embed directive, it is serialized to a ByteArrayAsset class immediately, which is a subclass of ByteArray. So you can do:

[Embed(source="sourceImg.png", mimeType="application/octet-stream")]
private var MyImage:Class;

var bytes:ByteArray = new MyImage();

Now all you need to do is write that ByteArray to the disk using FileStream:

var file:File = File.desktopDirectory.resolvePath('targetImage.png');
var fs:FileStream = new FileStream();
fs.open(file, FileMode.WRITE);
fs.writeBytes(bytes);
fs.close();

And that's all there is to it.

Flex with Java VS Coldfusion VS PHP

Question

I'm starting/learning to build Flex application with Flash Builder 4.5. The tutorial link me to http://www.adobe.com/devnet/flex/testdrive/articles/1_build_a_flex_app.html and I notice that you can use Flex with Java, Coldfusion or PHP. I'm wondering what are the differences between each of them and which one should I choose?

Thanks

Answer  (accepted and has 2 votes)

The problem is not that you can't extend ResourceManagerImpl since it's not final, but rather that you have to be able to register your implementation with the application instead of the default one. And doing this is a bit tricky.

So first create your implementation:

public class MyResourceManager extends ResourceManagerImpl {

    private static var instance:IResourceManager;

    static public function getInstance():IResourceManager
    {
        if (!instance) instance = new MyResourceManager();
        return instance;
    }

    override public function getStringArray(bundleName:String,
                                            resourceName:String,
                                            locale:String = null):Array {
        //do your stuff
    }

}

So we've overriden the getStringArray method. Notice that we've done the same for getInstance, because we want it to return a new instance of MyResourceManager instead of ResourceManagerImpl (we don't have to mark override because it's a static method). Also, you may have to write some import statements manually, because some of the classes you're using are marked as 'excluded'.

Now we have to tell Flex to use MyResourceManager instead of ResourceManagerImpl. We can do this with the following code:

import mx.core.Singleton;
Singleton.registerClass("mx.resources::IResourceManager", MyResourceManager);

The problem is that we have to do this before Flex registers ResourceManagerImpl, because you can't override it once it's registered. For this we need to create a custom preloader in which we do the registering (sadly, the Application's 'preinitialize' phase is not early enough).

public class RegisteringPreloader extends DownloadProgressBar {

    override public function initialize():void {
        super.initialize();
        Singleton.registerClass("mx.resources::IResourceManager", 
                                MyResourceManager);
    }

}

Now assign the custom preloader to the application and we're done:

<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"
               preloader="RegisteringPreloader" >

For further info I refer you to a fairly similar, but somewhat more elaborate answer that I wrote for a different question: Is there a way to listen for events on the pop up manager class?

Copying embedded file from "assets" to File.applicationStorageDirectory

Question

I need to copy some images I embedded in the "assets" folder of my project into the File.applicationStorageDirectory location, but I have no idea about how to do it (actually I don't know how to access the embedded file with a File object instance)...

Any suggestions ?

Answer  (accepted and has 1 votes)

You'll have to use File#browseForOpen() instead of FileReference#browse(), something like this:

private var f:File;

public function browseForRead():void {
    f = File.documentsDirectory;
    f.addEventListener(Event.SELECT, readFile); 
    f.browseForOpen("Open file");
}

private function readFile(event:Event):void {
    var stream:FileStream = new FileStream();
    stream.open(f, FileMode.READ);
    trace(stream.readUTFBytes(stream.bytesAvailable));
}

FileReference#browse() is used for uploading files in web applications.

Alter ResourceManager to split values by semicolon, not comma

Question

As the title says, is there a way to alter the ResourceManager's getStringArray() in a way that it splits the resources by semicolon, not comma?

The actual method can be found in the ResourceManagerImpl class, which can be found in in the package mx.resources. Overriding that method would be fine, but ideally I'd like to write my own getStringArray with a variable separator, however, there seems to be no way of extending either the ResourceManager or ResourceManagerImpl class to somehow add that method.

Anyone got a clue what to do here?

Answer  (accepted and has 3 votes)

ArrayLists and ArrayCollections (whichever you use as a 'dataProvider') both dispatch CollectionEvent.COLLECTION_CHANGE events to notify the List component (or CombBox in this case) that an item was added or removed.

So basically all you need to do, is removing the item from the dataProvider and the ComboBox will refresh automatically.

myComboBox.dataProvider.removeItemAt(myComboBox.selectedIndex);

(for this example code I'm assuming you're talking about a Spark ComboBox which only takes ILists as a dataProvider)

Read file opened via FileReference in Flex

Question

I have to browse for and open a file in AIR. I can access the file via the File class:

var file:File = File.applicationStorageDirectory.resolvePath("somefile.txt");
var stream:FileStream = new FileStream();
stream.open(file, FileMode.READ);

And I can browse for a file via the FileReference class:

var fileRef:FileReference = new FileReference();
fileRef.browse(allTypes);

But I cannot seem to get the file from the FileReference object into the File object.

There is no "path" member exposed when debugging the FileReference after opening it, any ideas?

Answer  (accepted and has 2 votes)

Just put the Validators in a collection (an Array for instance). After that you can simply loop over the collection's items.

<fx:Declarations>
    <fx:Array id="validators">
        <mx:StringValidator source="{firstnameInput}" property="text" required="true" />
        <mx:StringValidator source="{lastnameInput}" property="text" required="true" />
        <mx:EmailValidator source="{emailInput}" property="text" required="true" />
        <mx:DateValidator source="{dateInput}" property="text" required="false" />
    </fx:Array>
</fx:Declarations>

You can then simply use 'validateAll()':

Validator.validateAll(validators);

or loop over the Validators:

for each (var validator:Validator in validators) { ... }

Flex ComboBox - Refresh dataprovider

Question

I am using a combobox to list the contents of a folder.

With a button click I use that combobox.selectedItem to delete that folder. After I delete the data is still in the combobox. How do I go about refreshing that combobox?

Answer  (has 1 votes)

The big difference between FlashBuilder and Flash Pro is that the former will load all the referenced classes into memory. This is necessary for the code hinting (or intellisense), the automatic imports and the warning/error messages in the IDE to work (and probably some other functionalities that I'm not thinking of right now. If you make FB always load all classes you possibly have, then you're bound to hit a memory wall.

Therefor having one big project with all your classes is simply not a good approach. It also isn't from a maintainability point of view (in a team it would be a nightmare), but that's a different discussion. So I think you should reconsider it. Note that I understand your reluctance to do so, but in the long run it'll pay off to keep your dependencies more organized.

So the first thing you should do, is cutting that huge project into smaller pieces (library projects) that can stand on their own and then link only the dependencies you need into the main project. There are two main ways to link other projects in your main project. In the project properties, go to 'Flex library build path' and select the tab 'Library path'.

I hope this is enough info to get you started organizing your projects. I have also written another answer on a similar question with some performance and organizational tips that might be helpful to you: Flex 4.5 - to long build process

How to access an object's declarations with actionscript?

Question

I would like to iterate through an object's validators. Validators must be declared in a declarations tag. How does one scroll through declarations? If one cannot, is there a better of locating all validators other than scrolling through all properties of an object?

Answer  (accepted and has 2 votes)

There are two approaches here, depending on what you need. In either case the data you want are the children of the recommendedMaterials node, not the node itself (which is what you did).

materials_Cmb.dataProvider = 
    new XMLListCollection(xml_val.recommendedMaterials.children());

This should already do the trick. Note that I wrapped the XMLList in an XMLListCollection: this is not strictly necessary with the mx:ComboBox, because it will do the same internally, but for Spark components it would be mandatory.

Another more concise solution would be to just find all the 'value' nodes, but I don't know whether that approach fits your bill.

materials_Cmb.dataProvider = 
    new XMLListCollection(xml_val..value);

Also don't forget to assign the correct 'labelField' in the ComboBox:

<s:ComboBox labelField="@label" />

The @ sign represents an XML attribute.

I added class directory via Flex Build Path/Source Path, and now 'building workspace' takes forever

Question

I am coming from flash to flashbuilder.

I have a directory, AS3_classes_dir, on my computer that stores all of my classes, including my greensock and papervision packages. In every flash app that I make I include that directory in the Source Path, so that I can import whatever I may need. Compiling in flash (using ctrl/enter) takes very little time; only the classes that are specifically imported are compiled.

So today I did that in flashbuilder, included AS3_classes_dir via Flex Build Path/Source Path ... but now the compile time are a couple of minutes, even though I am not even importing ANY of the classes from within.

I do not have any other projects open.

Answer  (accepted and has 2 votes)

I'll assume you can use Spark DataGrid. In that case you just need to create a custom headerRenderer. To keep things simple we'll start from the default headerRenderer. In your Flex SDK sources, find the class spark.skins.spark.DefaultGridHeaderRenderer. Copy this file into your project and rename it appropriately.

Inside this class, find the components labelDisplayGroup and sortIndicatorGroup (they're at the bottom). They're inside an HGroup, so we can simply add our counter component in between.

<!-- I removed the original comments for brevity -->
<s:HGroup left="7" right="7" top="5" bottom="5" gap="2" verticalAlign="middle">
    <s:Group id="labelDisplayGroup" width="100%" />
    <!-- our counter component -->
    <s:Label id="numRowsDisplay" />
    <s:Group id="sortIndicatorGroup" includeInLayout="false" />
</s:HGroup>

So far for the visual component; now we have to update its text property appropriately. In the script block add the following snippet:

private var dp:IList;

override public function set owner(value:DisplayObjectContainer):void {
    if (dp) dp.removeEventListener(CollectionEvent.COLLECTION_CHANGE, updateNumRows);
    if (super.owner) super.owner.removeEventListener(PropertyChangeEvent.PROPERTY_CHANGE, onPropertyChange);

    super.owner = value;
    dp = value ? DataGrid(value).dataProvider : null;
    updateNumRows();

    if (dp) dp.addEventListener(CollectionEvent.COLLECTION_CHANGE, updateNumRows);
    if (value) value.addEventListener(PropertyChangeEvent.PROPERTY_CHANGE, onPropertyChange);
}

private function onPropertyChange(event:PropertyChangeEvent):void {
    if (event.property == 'dataProvider') {
        dp = event.newValue as IList;
        updateNumRows();
    }
}

private function updateNumRows(event:CollectionEvent=null):void {
    numRowsDisplay.text = (dp ? dp.length : 0) + "";
}

What happens here? the owner property of the renderer refers to the data component that holds this renderer; in this case a DataGrid. So when the owner is assigned to the renderer, we access its dataProvider and use its length to update the counter component.

So what are those listeners for? There are two cases you might want to foresee.

How to populate flex combo box with xml data

Question

here is the xml data :

<root>
    <recommendedMaterials>
        <value label="Aluminium" data="0" /> 
        <value label="Iron" data="0" /> 
    </recommendedMaterials>

</root

My code :

<mx:Script>
        <![CDATA[
public function populateRecommendedMaterials(xml_val:XML)           
            {
                 materials_Cmb.dataProvider=(xml_val.recommendedMaterials); 
            }

    ]]>

</mx:Script>        

    <mx:ComboBox x="212" y="164" id="materials_Cmb" dataProvider="materialsCmb_Dp"></mx:ComboBox>

</mx:Canvas>

The problem is that the whole xml gets populated. I just want the labels. :(

Answer  (has 2 votes)

You cannot use absolute constraints like 'x', 'y', 'left', 'right', 'top', 'bottom', 'horizontalCenter', 'verticalCenter', ... inside a relative layout like VerticalLayout (VGroup is just a Group with a VerticalLayout). This makes sense since you can't position something both relatively and absolutely. In this case the layout of the container takes precedence over whatever constraints you put on the child component. This means you can simply remove any of these constraints you have there: they simply don't have any effect.

Also 'verticalAlign' is a style you apply to a container, but it tells the container how to layout its children. You've assigned it to the Labels, so you're saying "lay out the text component inside the Label in the middle of the Label component" and not "layout the Label component in the middle of the VGroup". So this one is also redundant.

Something like the following should fix your issue:

<s:VGroup height="200">
    <s:Label text="A" height="50%" verticalAlign="middle" />
    <s:Label text="B" height="50%" verticalAlign="middle" />
</s:VGroup>

or if you want both Labels grouped together in the middle of the VGroup (it's not apparent from the description which one of both you want):

<s:VGroup height="200" verticalAlign="middle">
    <s:Label text="A" />
    <s:Label text="B" />
</s:VGroup>

How do I get my flex spark skin to center vertically?

Question

I've created a skin that allows me to have two labels on a spark button, but the button text won't center vertically. It stays at the top of the button no matter what settings I give it. The icon in the skin DOES however, center vertically.

This is the skin:

<s:SparkButtonSkin xmlns:fx="http://ns.adobe.com/mxml/2009" 
         xmlns:s="library://ns.adobe.com/flex/spark" 
         xmlns:fb="http://ns.adobe.com/flashbuilder/2009"
         minWidth="82" minHeight="82" 
         alpha.disabled="0.5" initialize="autoIconManagement=false">
<fx:Metadata>[HostComponent("com.XXXX.components.TwoLineButton")]</fx:Metadata>

<!-- states -->
<s:states>
    <s:State name="up" />
    <s:State name="over" />
    <s:State name="down" />
    <s:State name="disabled" />
</s:states>

<s:Image source="{getStyle('upSkin')}" 
         source.over="{getStyle('overSkin')}" 
         source.down="{getStyle('downSkin')}" 
         source.disabled="{getStyle('disabledSkin')}" 
         width="100%" height="100%"
         />

<s:HGroup verticalAlign="middle" height="100%" width="100%"
          paddingLeft="{getStyle('paddingLeft')}" 
          paddingRight="{getStyle('paddingRight')}" 
          paddingTop="{getStyle('paddingTop')}" 
          paddingBottom="{getStyle('paddingBottom')}"
          gap="{getStyle('horizontalGap')}" 
          verticalCenter="0">

    <s:BitmapImage id="iconDisplay" includeInLayout="{iconDisplay.source}"/>

    <s:VGroup gap="{getStyle('verticalGap')}" height="100%" width="100%">
        <s:Label id="labelDisplay"
                 textAlign="center"
                 width="100%"
                 maxDisplayedLines="1"
                 horizontalCenter="0" verticalCenter="1" verticalAlign="middle"
                 left="10" right="10" top="2" bottom="2">
        </s:Label>

        <s:Label id="bottomLabelDisplay"
                 textAlign="center"
                 width="100%"
                 maxDisplayedLines="1"
                 horizontalCenter="0" verticalCenter="1" verticalAlign="middle"
                 left="10" right="10" top="2" bottom="2">
        </s:Label>
    </s:VGroup>
</s:HGroup>

This is the code I'm calling it with:

<components:TwoLineButton
                width="308"
                label="TopLabel"
                bottomLabel="Bottom label"
                click="handleButtonClick(event)"
                />

I've tried making the HGroup use a hardcoded height value, and that doesn't work either.

Thanks in advance.

Answer  (accepted and has 5 votes)

When you create custom components in the Spark architecture, you usually split them up into two parts:

The first of these two classes is referred to as the host component from the skin's point of view.

A simple example

Let's create a very simple panel by extending SkinnableContainer:

public class MyPanel extends SkinnableContainer {

    [Bindable]
    public var title:String;

}

As you can see, I made a property 'title' which we want to use to display a title in the Panel. Now let's create a skin that uses this property:

<?xml version="1.0" encoding="utf-8"?>
<s:Skin xmlns:fx="http://ns.adobe.com/mxml/2009"
        xmlns:s="library://ns.adobe.com/flex/spark">

    <fx:Metadata>
        [HostComponent("path.to.MyPanel")]
    </fx:Metadata>

    <!-- graphics for title bar go here -->
    <s:Label text="{hostComponent.title}" top="5" left="5" />

    <!-- graphics for panel content go here -->
    <s:Group id="contentGroup" top="30" bottom="0" left="0" right="0" />

</s:Skin>

The hostcomponent is defined in the 'metadata' block and you see that we can use it to bind its properties into our visual representation. The 'contentGroup' is there because it is required by SkinnableContainer; this is were all the elements will go that you put inside the custom panel. So here's how to use it:

<myComps:MyPanel title="Panel title" skinClass="path.to.skins.MyPanelSkin">
    <s:Label text="Hello Panel" />
    <!--everything in here goes into the 'contentGroup'-->
</myComps:MyPanel>

Fex- Datagrid- custom header

Question

I want to put a textinput box on the header of a datagrid in flex, whose values changes dynamically according to the no of data or value present in that perticular column. Please any one help me, am posting the image acctually what I want. Thanks in advance.enter image description here

Answer  (accepted and has 2 votes)

Injecting by ID is not considerer to be good practice because you create a name-based dependency. Change the name, or make a typo, and your application breaks and it's hard to debug that.

So as a general rule you should try to avoid it. The Parsley docs explain how to do this. I'll just add a simple example to show you how you'd use that technique with your multiple RemoteObjects.

<fx:Object xmlns:fx="http://ns.adobe.com/mxml/2009" 
       xmlns:s="library://ns.adobe.com/flex/spark" 
       xmlns:p="http://www.spicefactory.org/parsley">

<fx:Script>
    import path.to.service.GenBusDelegate;
    import path.to.service.KarBusDelegate;
</fx:Script>

<fx:Declarations>
    <fx:String id="gateway">http://localhost:8080/ClinASM/messagebroker/amf</fx:String>

    <s:RemoteObject id="genBus" destination="genBus" endpoint="{gateway}" />
    <s:RemoteObject id="karBus" destination="karBus" endpoint="{gateway}" />

    <p:Object type="{GenBusDelegate}">
        <p:ConstructorArgs>
            <p:ObjectRef idRef="genBus" />
        </p:ConstructorArgs>
    </p:Object>

    <p:Object type="{KarBusDelegate}">
        <p:ConstructorArgs>
            <p:ObjectRef idRef="karBus" />
        </p:ConstructorArgs>
    </p:Object>

</fx:Declarations>
</fx:Object>

or if you don't want to use constructor arguments:

    <p:Object type="{GenBusDelegate}">
        <Property name="remoteObject" idRef="genBus"/>
    </p:Object>

What is the hostComponent?

Question

Im skinning a progressBar in Flex, and after reading a bit about it, I see that there is something called hostComponent.

Adobe site says:

"The host component is the component that uses the skin. By specifying the host component, Spark skins can gain a reference to the component instance that uses the skin by using the hostComponent property."

But, I still dont understand how this exactly works.

Any quick and practical explanation?

Thanks!

Answer  (accepted and has 1 votes)

I'll summarize our discussion for the pleasure of future readers.

Find the culprit

You could can have a look at the code of SkinnableTextBase to see what event listeners are attached internally. Now that you know that, you can use hasEventListener() to test which ones weren't removed. Using this technique we found that these listeners were still lingering:

Removing them (preferably without subclassing TextInput)

Have a look at the code of SkinnableTextBase where these listeners are registered:

override public function styleChanged(styleProp:String):void
{
    super.styleChanged(styleProp);

    if (!styleProp ||
        styleProp == "styleName" || styleProp == "interactionMode")
    {
        if (getStyle("interactionMode") == InteractionMode.TOUCH && !touchHandlersAdded)
        {
            addEventListener(MouseEvent.MOUSE_DOWN, touchMouseDownHandler);
            addEventListener(TouchInteractionEvent.TOUCH_INTERACTION_START,
                touchInteractionStartHandler);
            touchHandlersAdded = true;
        }
        else if (getStyle("interactionMode") == InteractionMode.MOUSE && touchHandlersAdded)
        {
            removeEventListener(MouseEvent.MOUSE_DOWN, touchMouseDownHandler);
            removeEventListener(TouchInteractionEvent.TOUCH_INTERACTION_START,
                touchInteractionStartHandler);
            touchHandlersAdded = false;
        }
    }
}

This means that if you set the TextInput's interactionMode style to InteractionMode.MOUSE, that should remove the listeners.


Note: you might want to take a look at the JIRA bug base and file a bug if noone already has. Though I must say I'm not sure if this JIRA is still maintained now that Flex is moving to Apache.

Flex mobile using Parsley

Question

I'm using Parsley in my flex mobile project. I have multiple destination services but I can't find more resources on how to add another destination service to config.xml file. The file is as below:

<objects 
    xmlns="http://www.spicefactory.org/parsley"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://www.spicefactory.org/parsley 
        http://www.spicefactory.org/parsley/schema/2.4/parsley-core.xsd">


    <object type="mx.rpc.remoting.RemoteObject" id="genBUS">
        <property name="destination" value="genBUS"/>
        <property name="endpoint" value="http://localhost:8080/ClinASM/messagebroker/amf" />
    </object>
</object>

In the case when I create another

<object type="mx.rpc.remoting.RemoteObject" id="anotherBUS"></objects>

and do

[Inject(id='genBUS')]
public var genBUS:RemoteObject;

it complains that I have defined multiple remote objects. How does it work? How can I inject another destination service? That would be great to gain more knowledge about Parsley...

UPDATE: config.mxml:

<?xml version="1.0" encoding="utf-8"?>
<mx:Object 
    xmlns:mx="http://www.adobe.com/2006/mxml"
    xmlns="http://www.spicefactory.org/parsley">


    <Object id="genBUS" type="mx.rpc.remoting.RemoteObject">
        <Property name="destination" value="genBUS" />
        <Property name="endpoint" value="http://localhost:8080/ClinASM/messagebroker/amf" />
    </Object>

    <Object id="karBUS" type="mx.rpc.remoting.RemoteObject">
        <Property name="destination" value="karBUS" />
        <Property name="endpoint" value="http://localhost:8080/ClinASM/messagebroker/amf" />
    </Object>


</mx:Object> 

Answer  (accepted and has 1 votes)

You cannot do this through styling; you'll have to create a custom skin. In order to do this in Flash-Builder: right-click in the project tree on the package where you want to create your skin. Select 'New', then select 'MXML Skin'. Fill out the wizard and choose to make a copy of the spark PanelSkin. This will copy the entire code of the default spark Panel skin into your custom skin class and you can now start adjusting it to your will.

Look for the group called 'topGroup': it contains all the elements of the top part of the Panel component. You can play around with this as you wish, but the easiest answer to your question is to locate the Label called 'titleDisplay'.

<s:Group id="topGroup" mask="{topGroupMask}">

    <!-- some other elements -->

    <s:Label id="titleDisplay" maxDisplayedLines="1"
             left="9" right="3" top="1" bottom="0" minHeight="30"
             verticalAlign="middle" textAlign="start" fontWeight="bold">
    </s:Label>

    ...

Do you see that 'minHeight' property? That's the one that is defining the height of the title bar. Just give it some more and you're ready to go.

You can apply the custom skin like so:

<s:Panel skinClass="path.to.my.CustomPanelSkin" />

Flex Spark Textinput prevents component to be collected by GC

Question

I've got a custom component (quite complex so I can't post any code here, although that shouldn't matter), that I can add to a view. When the component is deleted from the view or the view is switched I call my own dispose method which removes remaining eventListeners and kills some references so that the component can eventually be nulled and collected by the GC.

All that works perfectly fine until I add a Spark TextInput to the MXML part of the component (it took me hours to find out what is preventing the component to be collected!), so I recon that the TextInput somehow automatically adds some eventListeners.

My question is what are these listeners, or is there anything else I haven't thought of?

Any help would be greatly appreciated!

Answer  (accepted and has 4 votes)

What you refer to as "pass-through" styles are actually called inheriting styles. The solution to your question is in fact quite simple.

You use the style metadata on your custom component to declare that ButtonPanel has a stylename called 'buttonStyleName':

[Style(name="buttonStyleName", inherit="yes")]

public class ButtonPanel extends Panel {
     ....
}

Note the 'inherit' flag which is set to true: this will make sure that any component inside your custom Panel that has the same style will inherit the value that you've given to that style at the Panel level.

Setting this metadata will make sure that FlashBuilder will suggest buttonStyleName as a style and not as a property (as would happen with Sam's solution).


Edit: already defined styles

I didn't realize at first that you were referring to the mx ButtonBar (as it's not explicitly mentioned). The reason this is not working for you is that mx:ButtonBar already has these styles defined as not inheriting. Look at the source code:

[Style(name="firstButtonStyleName", type="String", inherit="no")]
[Style(name="buttonStyleName", type="String", inherit="no")]
[Style(name="lastButtonStyleName", type="String", inherit="no")]

Because of this the compiler will complain when you try to override that definition in your custom Panel, because it simply wouldn't know which of the contradictory instructions to pick. So we'll have to do a little more work if you want to stick with mx:ButtonBar.

First define the styles on ButtonPanel exactly as they are defined in mx:ButtonBar so they have the same signature (you can just copy/paste the three lines above). This will shut up the compiler but the styles won't be inherited anymore, right?

So we'll have to pass them on manually: in your custom Panel skin, override the updateDisplayList() method and - assuming that the ButtonBar's id is 'buttonBar' - add the following:

    private const buttonStyles:Array = [
        "firstButtonStyleName",
        "buttonStyleName",
        "lastButtonStyleName"
    ];

    override protected function updateDisplayList(unscaledWidth:Number, 
                                                  unscaledHeight:Number):void 
    {
        if (buttonBar) 
            for each (var buttonStyle:String in buttonStyles)
                buttonBar.setStyle(buttonStyle, getStyle(buttonStyle));

        //some other code

        super.updateDisplayList(unscaledWidth, unscaledHeight);
    }

This will take the styles from the host Panel and pass them on to the ButtonBar.

How to change the title bar height of spark.components.Panel?

Question

I'm creating a log-in box for my Flex application. However, I'm required to apply a specific design to this box that I have to change the title bar height.

The component I'm using is spark.components.Panel. I just can't find the property of this 'Panel' component to change the feature.

Any suggestions?

Answer  (has 1 votes)

I'll just summarize what we've been discussing so that other readers might benefit.

Let's look closely at the error message:

Could not register endpoint 'my-amf' because its URL, '/messagebroker/amf', is already used by endpoint 'my-amf2'

It speaks of '/messagebroker/amf' and doesn't mention the part of the URL before this, i.e. the part with the port number. From this we can derive that BlazeDS simply ignores this first part when it ascertains that two endpoints are identical or not. As such http://localhost:7001/dataservice1/messagebroker/amf and http://localhost:7002/dataservice2/messagebroker/amf would be considered identical even though they point to a different instance.

quick fix

A simple fix for this issue would be to simply rename the second endpoint after the last forward slash. For instance http://localhost:7001/dataservice1/messagebroker/amf2 should already do the trick. I don't think there is anything else you need to worry about since the MessageBroker servlet has a mapping with a wildcard after this last slash (/messagebroker/*) which will route any address formatted like this to the right servlet.

but why?

Perhaps you should reconsider why you're trying to do this. The reason that BlazeDS only checks the last part is that the developers probably simply didn't think of the fact that someone would actually try to point an endpoint to a different instance. Furthermore in your setup this other instance already has the same channel definition. You could simply connect to that channel so there is no need for this routing from the first instance. I have no idea what you're trying to achieve so all I can tell you is that you're probably approaching it from the wrong angle.

More than one channel in BlazeDS

Question

I am trying to set up a scenario where a Flex application would be able to use resources written in two different web application implementing BlazeDS.

I originally tried to do it by specifying a channel set in my mxml code and then setting this as the channel set of the service in mxml. However, although this worked, I was getting duplicate session errors.

It was suggested in one of the answers to my question linked to above that I could/should see about setting up channels with different endpoints. I guess this means that the Flex app will only be connecting to one service as it sees it but that the service will actually be delivering this service from another location as well.

I tried doing the following in my services-config.xml:

        <channel-definition id="my-amf" class="mx.messaging.channels.AMFChannel">
            <endpoint url="http://{server.name}:{server.port}/{context.root}/messagebroker/amf" class="flex.messaging.endpoints.AMFEndpoint"/>
        </channel-definition>

        <channel-definition id="my-amf2" class="mx.messaging.channels.AMFChannel">
            <endpoint url="http://localhost:7001/dataservice1/messagebroker/amf" class="flex.messaging.endpoints.AMFEndpoint"/>
        </channel-definition>

But I get the following errors in my weblogic console when trying to start up my server.

Could not register endpoint 'my-amf' because its URL, '/messagebroker/amf', is already used by endpoint 'my-amf2'

and

"MessageBrokerServlet" failed to preload on startup in Web application: "/dataservice2". flex.messaging.config.ConfigurationException: Could not register endpoint 'my-amf' because its URL, '/messagebroker/amf', is already used by endpoint 'my-amf2'

and

Unable to set the activation state to true for the application '_appsdir_DataService2_dir'. weblogic.application.ModuleException: [HTTP:101216]Servlet: "MessageBrokerServlet" failed to preload on startup in Web application: "/dataservice2".

I'm guessing that this is because you can only have one channel of class mx.messaging.channels.AMFChannel. Is this correct?

In general, is there a way around any of the problems I'm experiencing? I'm open to different solutions.

I've googled and read for hours and hours but can't find anything about this.

We want to have a common functionality service that is shared amongst all applications and an application specific service that provides services specific to that application.

Answer  (accepted and has 1 votes)

In this particular case I would go for the ToggleButton with a custom skin.

Why?

.

<s:ToggleButton id="loginBtn" selected.loggedin="true" selected.loggedout="false"
                skinClass="skins.FBLoginToggleButtonSkin" 
                click="logInOrOut(loginBtn.selected)" />

note: the two labels would be defined inside the custom ToggleButtonSkin:

<s:Label text="log in" text.selectedStates="log out" />

Defining a "pass-through" style in Actionscript

Question

I have a custom component called ButtonPanel written in Actionscript. Basically it's just a panel that displays a mx:ButtonBar in the upper right of the mx:Panel title bar and responds to the clicks of the buttons in the bar.

A ButtonBar has three styles available for the buttons: buttonStyleName, firstButtonStyleName, and lastButtonStyleName. I want to write these styles for the ButtonPanel so that if it is declared as such:

<comp:ButtonPanel buttonStyleName="myButtonStyle" ... />

then the ButtonPanel will pass the style through and set the corresponding style of the ButtonBar.

I really have no clue where to start on this because I've never messed with defining styles. Can someone help?

Answer  (accepted and has 1 votes)

This ought to do the trick:

<fx:Declarations>
    <s:Move id="moveEffect" />
</fx:Declarations>

<s:Group id="mapContainer" width="300" height="300" clipAndEnableScrolling="true"
         click="pan(event.localX, event.localY)">

    <s:Image id="map" source="@Embed('bigMap.png')" />
</s:Group>

'localX' and 'localY' are the mouse's 'x' and 'y' position relative to the mapContainer.

And now the pan() method:

private function pan(mouseX:Number, mouseY:Number):void {
    //calculate the offset from mapContainer's center
    var diffX:Number = mapContainer.width/2 - mouseX;
    var diffY:Number = mapContainer.height/2 - mouseY;

    //move the map through the move effect
    moveEffect.xFrom = map.x;
    moveEffect.yFrom = map.y;
    moveEffect.xTo = diffX;
    moveEffect.yTo = diffY;

    moveEffect.play([map]);
}

How to decode Json using native JSON or actionjson in Flex 3

Question

I have the below Json (wf.json)

{
"workflow":{
    "template":"Analysis1",

    "start":{
        "instance":"HDA_run1",
        "user":"symtest",
        "date":"3-Mar-2012",
        "timestamp":"1330948220475"
    },
    "host":{
        "name":"bartla",
        "user":"symtest1",
        "password":"symtest1",
        "installpath":"",
        "product":""
    },
    "javadump":{
        "pid":"8989",
        "corefilename":"",
        "heapdump":"",
        "stack":"",
        "JAVA_HOME":""  
    },
    "mat":{
    },
    "email":{
        "to":"[email protected]",
        "subject":"",
        "message":""
    },
    "end":{
    }
}
}

As you can see there are 7 items (or sub headings inside main heading workflow). Under each item it can have another set of properties eg: email (item) has 3 properties ("name":"value").

So based on the number of properties I need to be able to create controls (Text) in my Flex 3 UI.

I read here that actionjson is 5-6x faster than the as3corelib, but I am not able to find any example code for it. The actionjson doc says it function the same way as corelib, so I even tried import com.adobe.serialization.json.JSON; JSON.decode(rawData) but it is unable to find JSON.

Below is my code

<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" 
            layout="absolute" minWidth="955" minHeight="600"
            creationComplete="service.send()">

    <mx:Script>
    <![CDATA[

        import mx.controls.Alert;
        import mx.rpc.events.ResultEvent;

        private function onJSONLoad(event:ResultEvent):void
        {
            //get the raw JSON data and cast to String
            var rawData:String = String(event.result);
            //Alert.show(rawData); This prints my JSON String

            var obj:Object = decodeJson(rawData);   
            /*error call to possibly undefined method decodeJson*/
            Alert.show(obj.toString());
        }
    ]]>
    </mx:Script>

    <mx:HTTPService id="service" resultFormat="text"
                url="/cjb/wf.json"
                result="onJSONLoad(event)" />

</mx:Application>

Please help me fetch name, values if any from each item. Thanks

Is it not possible to directly fetch json data from an object (not custom made) like it is done in jquery?

Update with Flex Build Path

enter image description here

Answer  (accepted and has 5 votes)

It's as simple as giving your TabBar a TileLayout. You don't have to subclass TabBar and you don't even have to create a custom skin class for it. Just do this:

<s:TabBar dataProvider="{dp}" left="0" right="0">
    <s:layout>
        <s:TileLayout horizontalGap="-1" verticalGap="-1" 
                      requestedRowCount="2" />
    </s:layout>
</s:TabBar>

Which will produce something like this:

TabBar with TileLayout

The gap below the TabBar you saw, is produced because TileLayout will by default allocate a certain number of rows. You can override this by setting the requestedRowCount to the number of rows you expect (2 in this example).

If you want it to be truly dynamic, you can calculate the required number of rows by comparing the TabBar's total width to the TileLayout's columnWidth, and bind the resulting number to the requestedRowCount property.

Skinning a button in Flex through document states

Question

I came across this piece of code and it intrigued me. I haven't seen skinning like this before. I'd like to know if there are any downsides and alternatives to it. For example, is it cpu intensive like addChild calls are?

<s:Button id="loginoutBtn" right="10" top="10" label="Log out" label.loggedout="Log in" skinClass.loggedin="skins.FBLogoutButtonSkin" skinClass.loggedout="skins.FBLoginButtonSkin" click.loggedin="logout()" click.loggedout="login()"/>

Background: The button above is part of a Login example. I've worked with skinning a lot but the process has almost always resulted in a new component to go with the new skin. Also, would a ToggleButton but a good use case for the above?

A better question would be if you had to have a login and logout button in the x y location how would you do it?

I think in this case I'd have two buttons set to their relevant skins and a includeIn for each, so,

<s:Button id="loginBtn" includeIn="loggedIn" right="10" top="10" skinClass="skins.FBLoginButtonSkin" click="login()"/>

<s:Button id="logoutBtn" includeIn="loggedOut" right="10" top="10" skinClass="skins.FBLogoutButtonSkin" click="logout()" />

Answer  (accepted and has 5 votes)

If you just want to measure the loading time of the Flash object, you can just use FireBug. But if you want to know when a Flex application is completely ready for usage (i.e. all RSL's loaded; all initial data loaded), I think there are two approaches. One within the app, using a custom preloader to start timing and stop timing when your conditions are met. The other through JavaScript and ExternalInterface. Of which I reckon the latter will give you the most accurate result, because there will probably already be a delay before the preloader is loaded.

JavaScript and ExternalInterface

I have never done this so I'm just going to explain my thoughts. In Javascript you create a 'date' object when the Flash object starts loading. You're probably using SWFObject to inject the Flash object into the page, so you can probably hook up somewhere in there. Then inside your Flex application, when the necessary conditions are met (you define what those are), you use the ExternalInterface.call() to tell JavaScript that the Flex app is ready. Make a new 'date' and subtract the first 'date', and you have your loading time.

More info on using ExternalInterface can be found in the docs: http://help.adobe.com/en_US/as3/dev/WS5b3ccc516d4fbf351e63e3d118a9b90204-7cb2.html

more detail

Create the JavaScript function that we'll call when the app is ready:

function onFlexAppReady() {
    var end = new Date().getTime();
    var loadTime = end - start; //in ms.
}

Now in the code that was generated by FlashBuilder, add the start time before the swf is injected:

var start = new Date().getTime();
swfobject.embedSWF(
            "MyFlexApp.swf", "flashContent", 
            "100%", "100%", 
            swfVersionStr, xiSwfUrlStr, 
            flashvars, params, attributes);

Lastly, in your Flex app, when the right conditions are met, call the JavaScript function:

ExternalInterface.call("onFlexAppReady");

Again, this is all untested code, but it should get you started.

Clicked SWF/IMAGE position to center : FLEX

Question

Iam trying to make clicked position to center in flex. My code is

<fx:Declarations>
    <s:Parallel id="transformer" target="{swe}">
        <s:Scale id="scaleby" scaleXBy="0.2" scaleYBy="0.2" autoCenterTransform="false"/>           
    </s:Parallel>
</fx:Declarations>




   <s:Group width="500" height="350" clipAndEnableScrolling="true">
               <s:SWFLoader source="CasuarinaBigMap.swf"  width="500"   height="350" id="swe" click="swe_clickHandler(event)"/> 

 </s:Group>


protected function swe_clickHandler(event:MouseEvent):void
{
        scaleby.transformX = event.mouseX;
        scaleby.transformY = event.mouseY;
        transformer.play(); 
}

My qustion is How can I make clicked point pan into the center of the box? Pls help.

Thanks.

Answer  (accepted and has 1 votes)

If the fastest parser is what you want, then you'll want use native JSON parsing. Its usage is as simple as this:

var result:Object = JSON.parse(event.result);
trace(result.workflow.template);  //traces "Analysis1"

The JSON class is located in the root package, so no need to import anything. You can find information on its usage in the docs.

However native JSON is only available for Flash Player 11 or higher, which means you'll have to target at least that player version. Since your compiling a Flex 3 application, it will target Flash Player 9 by default. If your requirements don't prohibit you from targeting FP11+, the easiest fix is to compile with the Flex 4.6 (or higher) SDK. The screenshot in your question shows that you're using Flex 3.5, so you'll have to change that in the "build path" settings.


If you wish to traverse the resulting object dynamically, you can do it with a simple 'for' loop:

//workflow is the root node of your structure
var workflow:Object = result.workflow;
//iterate the keys in the 'workflow' object
for (var key:String in workflow) {
    trace(key + ': ' + workflow[key]);
}
//template: Analysis1
//start: [Object]
//host: [Object]
//...

If you want to do it recursively, you can check whether a value is an Object or not:

if (workflow[key] is Object) {
    //parse that node too
}
else {
    //just use the value
}

Flex : Multy row TabBar?

Question

Answer  (accepted and has 0 votes)

Your custom skin has no background fill, hence it's completely transparent except for the border. Because of this there is no "hitzone" to drop your items on (right now you will probably be able to drop them if you target exactly that 1px border).

The solution - obviously - is to give it a fill. No worries, if you want it to look transparent, just set its alpha to 0.

<s:Rect left="0" right="0" top="0" bottom="0" radiusX="5" radiusY="5">
    <s:fill>
        <s:SolidColor alpha="0" />
    </s:fill>
    <s:stroke>
        <s:SolidColorStroke alpha="0.50" />
    </s:stroke>
</s:Rect>

How to get the time which is spend for loading the flash object?

Question

Answer  (accepted and has 1 votes)

You have to re-set the linestyle too, so move

my_shape.graphics.lineStyle(2, 0x00FF00, 1);

to your moveLines() method, after the 'clear' of cource.

Custom Drag and Drop Component: When i add a skin, drag and drop no longer works?

Question

I have a skinnableContainer that acts as a container for other drag and droppable items. This container's drop functionality is added from it's parent at the same moment the container is added.

This all works fine until i add a skin class to the skinnableContainer, now none of the draggable items can drop into the container as it did before.

I assume that the Group component wrapping the content from within the skin is acting as a block somehow, but i'm not sure how to allow the drop functionality through it?

Any ideas? Thanks in advance.

EDIT skin code below:

<?xml version="1.0" encoding="utf-8"?>
<s:Skin xmlns:fx="http://ns.adobe.com/mxml/2009" xmlns:mx="library://ns.adobe.com/flex/mx" xmlns:s="library://ns.adobe.com/flex/spark" alpha.disabled="0.5">

<fx:Metadata>
    [HostComponent("spark.components.SkinnableContainer")]
</fx:Metadata> 

<s:states>
    <s:State name="normal" />
    <s:State name="disabled" />
</s:states>

<!-- layer 1: border -->
<s:Rect left="0" right="0" top="0" bottom="0" radiusX="5" radiusY="5">
    <s:stroke>
        <s:SolidColorStroke color="0" alpha="0.50" weight="1" />
    </s:stroke>
</s:Rect>

<s:Group id="contentGroup" left="0" right="0" top="0" bottom="0"  >
    <s:layout>
        <s:VerticalLayout/>
    </s:layout>
</s:Group>
</s:Skin>

Answer  (has 0 votes)

Flex SDK sources

You can find the latest source code through the Flex Apache incubator page and use Subversion to check it out. However since the migration of the Flex SDK from Adobe to the Apache foundation is still very much in progress, I sincerely doubt that there would already be significant changes that would fix your issues.

The actual issues

  1. XML parsing makes the whole application sluggish

XML parsing is a pure ActionScript matter and has nothing to do with Flex. It is closely related to how the Flash VM works, which is still closed property of Adobe. I don't think it is subject to change any time soon, mostly because I've heard very little complaints about its performance and the E4X language is one of the most powerfull around. If you're having performance issues better have a look at your architecture or work with AS model objects instead of XML.

  1. Russian input in TextInput doesn't work with Opera

This is either related to the Flash VM (see above) or to the Text Layout Framework, which is "open-source", but still in the hands of Adobe. Whether it should also be contributed to Apache Flex is still being discussed. In both cases very little will change in the short future, so I think you'll have to try another approach.

AS3 - Using graphics.clear not working as expected

Question

Would anyone know why using graphics.clear(); in this example is preventing the graphics from being drawn?

e.g. the following code works and the lines are drawn.

var my_shape:Shape = new Shape();
my_shape.graphics.lineStyle(2, 0x00FF00, 1);
addChild(my_shape);

function moveLines():void { 
my_shape.graphics.moveTo(10, 10); 
my_shape.graphics.lineTo(50, 50);
my_shape.graphics.lineTo(100, 100);
}

moveLines();

But if I add the clear() command nothing is drawn.

function moveLines():void { 
my_shape.graphics.clear();  
my_shape.graphics.moveTo(10, 10); 
my_shape.graphics.lineTo(50, 50);
my_shape.graphics.lineTo(100, 100);
}

moveLines();

I'm wanting to animate the line moving so would like to clear the previous drawing before redrawing the lines.

Thanks

Answer  (accepted and has 1 votes)

You should write your XML to the file as a String. Right now you're writing it as an XML object, which looks a lot like a String, but has some additional information. I think that strange character at the start represents the length of the String.

Use writeUTFBytes() instead of writeObject().

So replace

stream.writeObject(xml);

with

stream.writeUTFBytes(xml.toXMLString());

writeUTF() won't do the trick either: if you read the docs, you'll see that it writes the length of the String as the first character too.

How to update Flex SDK in Flash Builder 4.6

Question

As an owner of Flash Builder 4.6 I'm struggling with 2 problems in my web application:

  1. XML parsing makes the whole application sluggish
  2. Russian input in TextInput doesn't work with Opera

I wonder, if there is a new Flex SDK available for download, where some fixes might have been integrated since the Flash Builder 4.6 release several months ago.

So I have downloaded the "Flex SDK version 4.6.0.23201 is the latest production quality release" and installed it:

enter image description here

However this seems to be a version, which differs very little from the stock Flex SDK included with Flash Builder 4.6 originally.

My questions is: is there some good (i.e. fresh, but also tested/stable) source for Flex SDK, which would be suitable for Flash Builder 4.6?

Maybe I can check out the source from some repository and build it myself (how, please?).

Does Apache offer anything, since they are the new owners?

UPDATE:

I've checked out Apache's Flex with

svn co https://svn.apache.org/repos/asf/incubator/flex/trunk flex

(and have yet to figure out, how to build it) - isn't it newer and better?

Answer  (has 2 votes)

In actionscript:

myDataGrid.doubleClickEnabled = true;
myDataGrid.addEventListener(GridEvent.GRID_DOUBLE_CLICK, handleGridDoubleClick);

private function handleGridDoubleClick(event:GridEvent):void {
    trace(event.rowIndex, event.columIndex);
    trace(event.column, event.item);
}

Or in MXML:

<s:DataGrid doubleClickEnabled="true" 
            doubleClick="handleGridDoubleClick(event)" />

'doubleClickEnabled' is 'false' by default so you have to explicitly set it to 'true'

FileStream.writeObject produces unwanted characters

Question

I try to write an xml object via AIR with FileStream.writeObject

I'm doing like this:

var _file:File = File.applicationDirectory.resolvePath("test.xml");
var _xml:XML = new XML("<data><name>Testname</name><email>[email protected]</email><time>1331290186848</time></data>");

stream = new FileStream()
stream.open(_file, FileMode.WRITE);
stream.writeObject(xml);
stream.close();

unfortunately, this is the result

Å<data>
   <name>Testname</name>
   <email>[email protected]</email>
   <time>1331290186848</time>
</data>

since i don't have any influence on the process, how can i prevent AIR to write those strange chars?

thank you!

Answer  (accepted and has 2 votes)

How do I get itemDoubleClick event in spark DataGrid?

Question

Recently I am working with Spark DataGrid. Before I was using AdvancedDataGrid. In that I was capturing itemDoubleClick event. But I am not able to find such a event in SparkdataGrid.

So I want to capture double click event on single row of DataGrid.

Some people told that, I have to use my custom ItemRenderer to do that. But is there any way to capture itemDoubleClick event in Spark DataGrid without creating custom ItemRenderer ???

Answer  (accepted and has 3 votes)

var s:String = "2012/03/05";
var dateParts:Array = s.split('/'); //['2012', '03', '05']
//take off the first element and add it back at the end
dateParts.push(dateParts.shift());  //['03', '05', '2012']
s = dateParts.join('/');            //'03/05/2012'
trace(s);

ActionScript Get All Network Activity?

Question

Is there a way within ActionScript 3.0 to:

Since my application contains SWC files which were compiled by another developer, I cannot directly access the ActionScript which creates the URL requests and RTMP connections.

Thank your for your time.

Answer  (accepted and has 1 votes)

the reason

You are adding the new array allright, but then the List starts creating ItemRenderers based on the items that are in that array. This takes some time and happens asynchronously. In the meantime you're saying "show me item 1", but the ItemRenderer for item 1 doesn't exist yet. It will very soon, but not right now. That's why you get an indexoutofrange error.

the solution

You have to be sure the List is done creating ItemRenderers before you call that method. The easiest way to solve this situation - though definitely not the cleanest - is to just wait until the next render cycle by using the infamous callLater().

callLater(_list.ensureIndexIsVisible, [0]);

This essentially saying: wait for the next render cycle and then call ensureIndexIsVisible() on _list with parameter 0.

(On a side note: if you really only want index 0 this whole thing is rather pointless, because I think a List scrolls back to the top when its dataprovider is changed anyway)

a cleaner solution

You can listen on the List for the RendererExistenceEvent#RENDERER_ADD event. This will be dispatched whenever a new ItemRenderer was added to the list and it holds a reference to the item's index in the List, the data and the ItemRenderer itself. However in your case we only need the 'index'. Whenever an ItemRenderer is added at index 0 we'll scroll back to the top:

_list.addEventListener(RendererExistenceEvent.RENDERER_ADD, onRendererAdded);

private function onRendererAdded(event:RendererExistenceEvent):void {
    if (event.index == 0) myList.ensureIndexIsVisible(0);
}

This will immediately scroll to the top when the first ItemRenderer is added and doesn't need to wait until all of them are ready.

convert Date Format yyyy-mm-dd to dd-mm-yyyy in flex

Question

I have a requirement. I have a date format as yyyy/mm/dd and I want to convert this format to mm/dd/yyyy in action script.

I had tried to parse to this format, it is not working. Can any one of you please help me?

Answer  (accepted and has 1 votes)

You can use the ItemRenderer's depth property to achieve this. Just set it to 0 when the renderer is not selected and set it to 1 when it is.

Christophe Coenraets wrote a very clear article (with example) on this. No need for me to add anything to that.

http://coenraets.org/blog/2010/01/cool-itemrenderers-made-easy-in-flex-4/

The first example is the one you want. This example uses the 'hovered' state instead of 'selected', but the idea is the same.

ArayList as dataProvider for a List: The index 0 is out of range 0

Question

Does anybody please have an idea, why do I get the runtime error:

RangeError: Error #1125: The index 0 is out of range 0.
    ........
    at Popup/update()[Popup.mxml:80]
    at PopupTest/showPopup()[PopupTest.mxml:45]
    at PopupTest/___btn_click()[PopupTest.mxml:52]

when calling the function:

private function showPopup(event:MouseEvent):void {
    _popup.update(new Array('Pass' , 
        '6♠', '6♣', '6♦', '6♥', '6 x', 
        '7♠', '7♣', '7♦', '7♥', '7 x', 
        '8♠', '8♣', '8♦', '8♥', '8 x', 
        '9♠', '9♣', '9♦', '9♥', '9 x', 
        '10♠', '10♣', '10♦', '10♥', '10 x'), true, 80);
}

As if my _list would have no entries at all (but why? I do assign _data.source=args) and thus the _list.ensureIndexIsVisible(0) call would fail at the line 80:

<?xml version="1.0" encoding="utf-8"?>
<s:Panel 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="220" height="200"
    initialize="init(event)">   

    <fx:Script>
        <![CDATA[
            import mx.collections.ArrayList;
            import mx.events.FlexEvent;
            import mx.utils.ObjectUtil;

            private static const FORCE:uint = 20;

            [Bindable]
            private var _data:ArrayList = new ArrayList();

            private var _timer:Timer = new Timer(1000, 120);

            private function init(event:FlexEvent):void {
                _timer.addEventListener(TimerEvent.TIMER, timerUpdated);
                _timer.addEventListener(TimerEvent.TIMER_COMPLETE, timerCompleted);
            }

            public function close():void {
                _timer.reset();
                _data.source = null;
                visible = false;
            }

            private function timerUpdated(event:TimerEvent=null):void {
                var seconds:int = _timer.repeatCount - _timer.currentCount;
                title = 'Your turn! (' + seconds + ')';
                // show panel for cards too
                if (seconds < FORCE)
                    visible = true;
            }

            private function timerCompleted(event:TimerEvent=null):void {
                title = 'Your turn!';
                close();
            }

            public function update(args:Array, bidding:Boolean, seconds:int):void {
                if (seconds <= 0) {
                    close();
                    return;
                }

                // nothing has changed
                if (ObjectUtil.compare(_data.source, args, 0) == 0)
                    return;
                _data.source = args;

                if (args == null || args.length == 0) {
                    close();
                    return;
                }

                if (seconds < FORCE || bidding)
                    visible = true;

                _timer.reset();

                title = 'Your turn! (' + seconds + ')';
                _list.ensureIndexIsVisible(0); // the line 80
                _timer.repeatCount = seconds;
                _timer.start();
            }
        ]]>
    </fx:Script>

    <s:VGroup paddingLeft="10" paddingTop="10" paddingRight="10" paddingBottom="10" gap="10" width="100%" height="100%">
        <s:List id="_list" dataProvider="{_data}" width="100%" height="100%" fontSize="24" itemRenderer="RedBlack" />
    </s:VGroup>
</s:Panel>

Answer  (accepted and has 3 votes)

I know this is not what you want to hear, but here it goes anyway: why do you want to do that? The whole purpose of the states is that you wouldn't have to write tons of ActionScript to do the same thing.

Why you can't do it like that

By writing Btn.enabled.State1 in ActionScript you're essentially saying: give me the property called 'State1' of the Boolean instance called 'enabled'. Obviously that won't work because a Boolean doesn't have such a property. You're confusing the MXML dot (.) notation - used for assigning values to properties based on states - with the ActionScript dot notation - used for reading/writing properties.

A solution or as close as it gets

Since it's the very nature of this feature that you would use it in MXML, you can't do exactly what you're asking for in ActionScript. The next best thing would be to listen for StateChangeEvent en set the Button's 'enabled' property according to the new state name.

addEventListener(StateChangeEvent.CURRENT_STATE_CHANGE, onStateChange);

private function onStateChange(event:StateChangeEvent):void {
    switch (event.newState) {
        case "wrong":   Btn.enabled = false; break;
        case "correct": Btn.enabled = true; break;
    }
}

(I'm using the same states as in James' answer)

Bring DisplayObject on top in DataGroup

Question

I have DataGroup with custom item renderers, which can partly overlap each other. I have possibility to select these items. And I want selected item to be above others in the datagroup. But since DataGroup sets childIndexes (from left to right) to its children and we cannot change childIndex of items explicitly, selected item is above all items to the left and under all items to the right. So, what is the way to place selected item above others? I thought of using PopUpAnchor, but may be other solutions exist. Thanks

Answer  (accepted and has 2 votes)

You want to create a client-side service stub for your remote service. There's a few steps to get this set up properly.

Create the service interface

For brevity we'll create an interface with just one method, but you can add as many as you need.

package be.vmm.user.service {
    import mx.rpc.AsyncToken;

    public interface ICustomerService{      
        function getCustomerById(id:int):AsyncToken;        
    }
}

Create an implementation of the interface

In your example you are extending RemoteObject. I would suggest you encapsulate it: that would be a lot more flexible. Not to mention that in your code the connection information is hardcoded which requires you to recompile your application every time this info changes.

public class CustomerService implements ICustomerService {
    private var ro:RemoteObject;

    public function CustomerService(ro:RemoteObject) {
        this.ro = ro;
    }

    public function getCustomerById(id:int):AsyncToken {
        return ro.getCustomerById(id);
    }

}

You also have the option to create another implementation of the interface. The most common use case consists of creating a mock service that doesn't really connect to the server but returns fake data directly. If you want to test your application without server connection you can now just substitute your real service stub with the mock service stub, since they both implement the same interface.

Use the implementation

var ro:RemotObject = new RemoteObject();
ro.destination = "customerService";
ro.source = "customerService";
ro.endpoint = "http://localhost/amfphp/gateway.php";
ro.showBusyCursor = true;
//these properties are best externalized in a configuration file

var service:ICustomerService = new CustomerService(ro);
var token:ASyncToken = service.getCustomerById(1);
token.addResponder(new Responder(handleResult, handleFault));

private function handleResult(event:ResultEvent):void {
    //do what you need to do
    trace(event.result as Customer);
}

private fucntion handleFault(event:FaultEvent):void {
    //show error message
}

Flex How to change button state in actionscript?

Question

i can do this:

<s:Button id="Btn" enabled.State1="false" />

But the following code is giving me an error.

 private function enableDisable():void{
       Btn.enabled.State1="false";  //Error: Access of undefined property State1
      }

how to code enabled.State1 in ActionScript?

Thanks

Answer  (accepted and has 1 votes)

Two steps:

  1. Have your custom Skin extend SparkButtonSkin instead of simply SparkSkin.
  2. Set the icon style of your Button

 <s:Button icon="@Embed('/path/to/my-icon.png')" 
           skinClass="path.to.MyButtonSkin" />

Flex Extend remote object

Question

My current coding for remote object declaration is messed up I wanna separate the remote object and the interface

Current Code :

    <s:RemoteObject id="ro"
                    destination="customerService" 
                    source="customerService" 
                    endpoint="http://localhost/amfphp/gateway.php"
                    showBusyCursor="true">
        <s:method name="getCustomer" result="getCustomer_resultHandler(event)">
            <s:arguments>
                <CusOpt>{''}</CusOpt>
                <option>{''}</option>
                <idcompany>{2}</idcompany>
            </s:arguments>
        </s:method>
        <s:method name="genPKID" result="genPKID_resultHandler(event)">
            <s:arguments>
                <idcompany>{2}</idcompany>
            </s:arguments>
        </s:method>
    </s:RemoteObject>   

now I am puzzled where to add the s:methods in a class like this ? and how to call it from another mxml file or component ?

import mx.rpc.remoting.RemoteObject;


    public class CustomerRO extends RemoteObject
    {
        public function CustomerRO(destination:String=null)
        {
            super(destination);
            this.destination = "customerService";
            this.source = "customerService";
            this.endpoint = "http://localhost/amfphp/gateway.php";
            this.showBusyCursor = true;
        }
    }

Answer  (accepted and has 0 votes)

The Animate#target property does not evaluate string values to object ID's. You have to bind the target element instead (or it will try to find the property endAngle on the String "arc", which will throw the error you're getting):

<s:Animate id="effect" duration="2000" target="{arc}">
    <s:SimpleMotionPath property="endAngle" valueFrom="90" valueTo="180" />
</s:Animate>

Note the only difference between your version and mine is the curly braces {}

different icons for the same Button skin flex

Question

I have the skin below for my buttons:

<?xml version="1.0" encoding="utf-8"?><s:SparkSkin 
xmlns:fx="http://ns.adobe.com/mxml/2009" 
xmlns:s="library://ns.adobe.com/flex/spark" 
xmlns:mx="library://ns.adobe.com/flex/halo"
>
<!-- host component -->
<fx:Metadata>
    <![CDATA[
    [HostComponent("spark.components.Button")]
    ]]>
</fx:Metadata>  

<!-- states -->
<s:states>
    <s:State name="up" />
    <s:State name="over" stateGroups="overStates"/>
    <s:State name="down" stateGroups="overStates" />
    <s:State name="disabled" />
</s:states>

.....
 </s:SparkSkin>

I was wondering how I can add a different image for different buttons which have the same skin.

Answer  (accepted and has 0 votes)

You're not supposed to set the Skin's currentState directly from within the Skin because the hostComponent should take care of that. When you deactivate and re-activate the Window, the hostComponent will set the Skin state back to one of its original states (e.g. normal) and hence disregards your two custom states.

If you want to set the Skin's state based on certain conditions you should override the getCurrentSkinState() method of the hostComponent. But in this particular case I don't think that would be the right approach, because it would be too complicated.

The easiest solution here I think would be to override the Skin's updateDisplayList() method to position your elements. This is the method that takes care of correctly displaying all the elements in your Skin.

<fx:Script>
    <![CDATA[
        override protected function updateDisplayList(unscaledWidth:Number, unscaledHeight:Number):void {
            super.updateDisplayList(unscaledWidth, unscaledHeight);

            if (NativeApplication.supportsDockIcon) {
                titleDisplay.left = width / 2;
                //position other elements for mac
            }
            else {
                titleDisplay.left = 60;
                //position other elements for win
            }
        }
    ]]>
</fx:Script>

Another - perhaps even better - approach would be to create two separate Skin's (one for Mac, one for Windows) and apply the correct Skin to your Windows. This would rid us of the continous if/else checking for capabilities.

How to animate a custom graphic component property

Question

I created a custom timer component, which basically renders a circle sector, with a default start angle (0) and an end angle:

public class Arc extends FilledElement
{
    private var _endAngle:Number = 0;

    public function Arc()
    {
    }

    public function get endAngle():Number
    {
        return _endAngle;
    }

    public function set endAngle(value:Number):void
    {
        if (_endAngle == value)
            return;

        _endAngle = value;
        invalidateDisplayList();
    }

    // left out the rendering logic, for clarity
}

Works fine and dandy so far. This is the code which renders the sector:

<org:Arc id="arc"
     endAngle="135">
    <org:fill>
        <s:SolidColor color="#FFFF00" />
    </org:fill>
</org:Arc>

However, I want to animate the endAngle property. This is the MXML code which aims to achieve this:

<s:Animate id="effect"
       duration="2000"
       target="arc">
    <s:SimpleMotionPath property="endAngle"
            valueFrom="90"
            valueTo="180" />
</s:Animate>

The problem is then when I play the effect, I get this error: Error: Property endAngle is not a property or a style on object arc: TypeError: Error #1006: value is not a function..

Has anyone else encountered this problem, or better yet, does anyone know what I did wrong and how to fix this problem?

Thank you.

Answer  (accepted and has 1 votes)

Summary


Turn off auto-build

First thing to do when you install FlashBuilder is turning off the automatic building "feature". The Flex compiler is waaay to slow to constantly build in the background unless you work on very small projects. It's in menu > Project > Build Automatically.

enter image description here

Close unrelated projects

Any open project eats away memory. Close as many as you can.

Remap Ctrl+B

Since you use the Ctrl+B keybinding to launch the build process, you should know that this will actually build your entire workspace. Every single project that is open will be built. When you have a lot of dependencies that's gonna take a whole lot of time.

That's why I remap the Ctrl+B combo to just build the project that I'm currently working on. A small donwside is that sometimes you have to go 'manually' build a few projects, but that's largely outweighed by the time gain.

Go to menu > Window > Preferences. Type "key" in the search box. Click the topic "keys" under "general". Now type "build" in the searchbox on the right. Select "Build Automatically" and click the "Unbind Command" button. The ctrl+B binding should disappear. Now select "Build Project", then select the "Binding" input field (lower left) and hit Ctrl+B. Save and you're done.

enter image description here

Encapsulate application domains

I don't have a single project that is bigger than 200 files (usually even less than 100). Since your project consists of 1300 files I assume that it is does not have one monolithic function. So you should be able to slice it up into separate libraries; preferably one for each application domain. This will allow you to compile sizeable bits of the application and has the added benefit of clearly separating some concerns within your application.

window skin according OS

Question

I try to have a specific window skin according operating system.

See below my skin.

    <s:SparkSkin xmlns:fx="http://ns.adobe.com/mxml/2009"
         xmlns:s="library://ns.adobe.com/flex/spark"
         xmlns:fb="http://ns.adobe.com/flashbuilder/2009"
         xmlns:Layout="skin.Layout.*"
         alpha.disabledGroup="0.5"
         creationComplete="sparkskin1_creationCompleteHandler(event)">

<fx:Metadata>
    [HostComponent("fr.inter.ui.windowSkin.wCustomWindow")]
</fx:Metadata>


<fx:Script>
    <![CDATA[
        import mx.events.FlexEvent;
        protected function btResize_mouseDownHandler(event:MouseEvent):void
        {
            btResize.addEventListener( MouseEvent.MOUSE_UP, btResize_mouseUpHandler );
            stage.nativeWindow.startResize();
        }

        protected function btResize_mouseOutHandler(event:MouseEvent):void
        {
            btResize.removeEventListener( MouseEvent.MOUSE_OUT, btResize_mouseOutHandler );             
        }


        protected function btResize_mouseUpHandler(event:MouseEvent):void
        {
            btResize.removeEventListener( MouseEvent.MOUSE_UP, btResize_mouseUpHandler );



        }

        protected function sparkskin1_creationCompleteHandler(event:FlexEvent):void
        {

            if (NativeApplication.supportsDockIcon)
            {
                this.currentState = "supportsDockIcon";//mac
            }
            else
            {
                this.currentState = "supportsSystemTray";
            }
        }


    ]]>
</fx:Script>


<s:states>
    <s:State name="disabledAndInactive" stateGroups="disabledGroup, inactiveGroup" />
    <s:State name="maximizedGroup"/>
    <s:State name="normal" />
    <s:State name="disabled" stateGroups="disabledGroup" />
    <s:State name="normalAndInactive" stateGroups="inactiveGroup" />
    <s:State name="supportsDockIcon" />
    <s:State name="supportsSystemTray"/>
</s:states>

<s:Rect id="backgroundRect"
        left="0"
        right="0"
        top="0"
        bottom="0"
        alpha="0"
        >
    <s:fill>
        <s:SolidColor alpha="0"/>
    </s:fill>
</s:Rect>

<s:Group bottom="0" left="0" right="0"
         top="0"  
         >
    <!--Fond de la fenetre-->
    <s:Rect bottom="0" left="0" right="0"
            top="0"
            radiusX="8" radiusY="8" >
        <s:fill>
            <s:SolidColor color="#656565" alpha=".7" />
        </s:fill>
        <s:stroke>
            <s:SolidColorStroke color="#666666" />
        </s:stroke>
    </s:Rect>

    <s:Group height="38" id="moveArea"
             left="0" right="0" >

        <!--Barre bleu avec filet-->
        <s:Rect  height="25" left="10" right="10" top="10">
            <s:fill>
                <s:SolidColor color="#055a90" />
            </s:fill>
            <s:stroke>
                <s:SolidColorStroke color="#666666" />
            </s:stroke>
        </s:Rect>


        <s:BitmapImage id="icon"
                       left.supportsSystemTray="5" right.supportsDockIcon="5"
                       verticalCenter="0" />

        <s:Label id="titleDisplay"
                 styleName="swindowTitle"
                 left.supportsSystemTray="60" left.supportsDockIcon="{this.width/2}"
                 top="18" verticalAlign="middle" horizontalCenter="0"
                 />

        <!--Zone de bouton-->

        <s:HGroup right.supportsSystemTray="12" left.supportsDockIcon="12" verticalCenter="0">

            <s:Button id="btMinimize" buttonMode="true" 
                      skinClass.supportsSystemTray="skin.components.MinimizeButtonSkin"
                      skinClass.supportsDockIcon="skin.components.MinimizeButtonSkinM"
                      verticalCenter="0"/>

            <s:Button id="btMaximize" buttonMode="true" 
                      skinClass.supportsSystemTray="skin.components.MaximizeButtonSkin"
                      skinClass.supportsDockIcon="skin.components.MaximizeButtonSkinM"
                      verticalCenter="0"/>

            <s:Button id="closeButton" buttonMode="true" 
                      skinClass.supportsSystemTray="skin.components.CloseButtonSkin"
                      skinClass.supportsDockIcon="skin.components.CloseButtonSkinM"
                      verticalCenter="0"/>

        </s:HGroup>

    </s:Group>

    <!--Fond de la zone principale-->

    <s:Rect id="background" left="10" top="35" right="10" bottom="10">
        <s:fill>
            <s:LinearGradient rotation="-90">
                <s:GradientEntry color="#edf0f7"/>
                <s:GradientEntry color="#fcfbfb" />
            </s:LinearGradient>
        </s:fill>
        <s:stroke>
            <s:SolidColorStroke color="#666666" />
        </s:stroke>
    </s:Rect>

    <!--Zone dans laquelle les elements vont se positionner-->


    <s:Group id="contentGroup" left="15" right="15" top="43" bottom="15" minWidth="0"
             minHeight="0" width="100%" height="100%">

    </s:Group>



</s:Group>
<s:Button height="15" id="btResize" width="15"
          bottom="0" right="0"
          skinClass="spark.skins.spark.windowChrome.GripperSkin" 
          mouseDown="btResize_mouseDownHandler(event)"
          buttonMode="true"/>

When windows is loading firt, buttons appear well. But if window is desactivate and after activate, MacOs and Windows buttons appear.

I don't know how to solve that, could you help me?

Thanks

Answer  (accepted and has 0 votes)

As far as I can tell from the code you show, the easiest solution to your problem would be to work with two separate ItemRenderers: one that renders text and the other that renders images. You can do this using the SkinnableDataContainer#itemRendererFunction property instead of itemRenderer.

The List with the new property:

<s:List id="myList" dataProvider="{dp}" 
        itemRendererFunction="getItemRenderer" />

The function that returns a factory for the right ItemRenderer.

private function getItemRenderer(item:Object):IFactory {
    if (data.msg_type == "text") 
        return new ClassFactory(MyTextItemRenderer);
    if (data.msg_type == "image") 
        return new ClassFactory(MyImageItemRenderer);
}

In these two different ItemRenderers you can then display your data as you wish.


Edit: why it's OK that the dataChange event fires every time you scroll.

There is in fact nothing wrong with your approach as you describe it, although I would argue that the itemRendererFunction approach allows for better separation of concerns. I could tell you that you can turn the unwanted behavior off, simply by setting the List#useVirtualLayout property to false.

<s:List id="myList" dataProvider="{dp}" 
        itemRenderer="myItemRenderer" useVirtualLayout="false" />

Though this will do what you ask for (i.e. create the ItemRenderers only once), that would not be good advice. There is a good reason this property is set to true by default.

When virtual layout is used, item renderers are created only as they are needed, i.e. when they come into view and need to be displayed to the user. This allows you to load thousands of items without performance loss.

Let's say you load 1000 value objects: that doesn't take up much memory or CPU. But now you want to render them. If you don't use virtual layout an item renderer will be created for all of them up front, which means thousands of graphic elements and thousands of event listeners (how many exactly depends on your setup). Now that is going to hurt performance on a slow computer.

If you do use virtual layout only - say - 10 item renderers will be created at once. If the user scrolls down, the next 10 will be created and the ones that just disappeared from the view are removed and eventually garbage collected. So you see: what you may have perceived as something that was bad for performance at first, is actually a very good thing.

So I would advise you not to do what I just told you. Unless perhaps you would have a situation where you knew there would never be more than a very limited number of items in your List. Then you may consider not using virtual layout.

Flex 4.5 - to long build process

Question

We are developing an app using flex 4.5. The app runs just fine (no performance issues at all) but it takes us forever to compile and build it. A minor change, like just add a comment or press enter in an mxml file and rebuild takes about 3 minutes. You just cant work that way.

It is a large project with about 1300 files. We also use Parsley as IOC container and a beat of cairngorm navigation. We also use Maven (Flex mojos) but I am talking about a normal eclipse build (Ctrl + B).

We separated some of the code to a different SWC and all of our graphics are stored in a different resource SWF.

Please, Do you have any suggestions?

Regards, Ido

Answer  (accepted and has 3 votes)

List#selectedIndex refers to the position of the selected item in the dataprovider. The first element will have index 0, the second index 1 and so on. If no item is selected, selectedIndex will be -1.

If you want to select or delete by firstName - as you do in your query - you will have to pass in a valid first name instead of an index position. You can do this with the List#selectedItem property. Also don't forget the single quotes in your query if you're not using query params.

"DELETE FROM UserTable " +
"WHERE firstName = '" + listBox.selectedItem.firstName + "'";

You weren't asking for this, but I'll tell you anyway: for security reasons you should use query params when using variables in your queries. One way to achieve this in ActionScript is:

stmt.parameters[0] = listBox.selectedItem.firstName;
stmt.text = "DELETE FROM UserTable WHERE firstName = ?";

(no single quotes required here)

Flex List item renderer

Question

I have created an item renderer spark list in flex , but i want to call a function on addition of new row in list and not afterwards. I am getting a data object in rendered list in it i am getting the type of data to be displayed in list ie. either text or image. So on addition of new data in list i want a function to be called up in rendered list that checks the type of data received and then it will either create and add an image element or a text element. So the main problem is how i get a function called on addition of data. I have tried events like datachange and added but they keep on calling the function over and over again when we scroll the list but i want the function to be called once only on addition of data and not after wards. Below is the renderer list code , maybe you will get a better idea of what i am trying to do:

<s:ItemRenderer xmlns:fx="http://ns.adobe.com/mxml/2009" 
                xmlns:s="library://ns.adobe.com/flex/spark" 
                xmlns:mx="library://ns.adobe.com/flex/mx" 
                autoDrawBackground="true" dataChange="test_add()">

    <fx:Script>
        <![CDATA[
            import mx.controls.Alert;
            public function test_add() : void {
                Alert.show("type="+data.msg_type);      
                if(data.msg_type=="text"){
                    //code to create and add new text element to list_row//
                }
                if(data.msg_type=="image"){
                    //code to create and add new image element to list_row//
                }
            }

        ]]>
    </fx:Script>

    <s:Group id="list_row" width="100%" verticalAlign="middle"  verticalCenter="0">

    </s:Group>
</s:ItemRenderer>

Any help will be highly appreciated. Thanks

Answer  (accepted and has 2 votes)

keyle's answer will only give you the height of the text, not the actual 'lineHeight' style. You can easily get that style like this:

myLabel.getStyle("lineHeight");

The problem is that this can return a relative value (a percentage) or an absolute value (in pixels). The default - if no lineHeight was explicitely set - is "120%".

So here's how we can get the value in pixels in both cases:

var lineHeightStyle:* = myLabel.getStyle("lineHeight");

//its already a value in pixels
if (lineHeightStyle is Number) var lineHeight:Number = lineHeightStyle;
//it's a relative value: let's calculate
else {
    var lineMetrics:TextLineMetrics = myLabel.measureText(myLabel.text);
    //get the numeric value from the string and divide it by 100
    var ratio:Number = int(lineHeightStyle.match(/\d+/)[0]) / 100;
    lineHeight = lineMetrics.height * ratio;
}

Flex SQLite delete function

Question

I wanted to delete a selected Item from a List control but can't. What's wrong with my code:

[Bindable]private var dp:ArrayCollection = new ArrayCollection();
private var conn:SQLConnection;

protected function Delete(event:MouseEvent):void    {
    Stmt = new SQLStatement();
    Stmt.sqlConnection = conn;
    Stmt.text = "DELETE FROM UserTable WHERE firstName="+listBox.selectedIndex;
    Stmt.execute();
}

<s:List id="listBox" itemRenderer="UserRenderer"></s:List>



In UserRenderer:

<s:ItemRenderer xmlns:fx="http://ns.adobe.com/mxml/2009"
                xmlns:s="library://ns.adobe.com/flex/spark">

    <s:Label text="{data.lastName}, {data.firstName}, {data.id}"/>

</s:ItemRenderer>

Answer  (accepted and has 1 votes)

I recently started building with Gradle and the GradleFx plugin and I immediately fell in love with its power and ease of use.

Gradle is ANT + Maven + Ivy evolved and is primarily used from the command-line. You can:

And best of all: it's very easy to learn. I had no knowledge of Maven before I started with Gradle and could get a multi-project build with some customizations working quite quickly.

Edit (comparison to Buildr AS3 and Maven)

I can compare this only to one of the projects you mentioned: Buildr AS3. It seems to start from a philosophy that is similar to Gradle's. But I've tried to use it about half a year ago and couldn't even get a simple 'Hello World' app to work. I e-mailed the developer for help: no response.

Compared to GradleFx: I had a small forum discussion with the developer (on a rather philosophical topic, since I didn't really need any help because it just worked right away). He answered within minutes.

As for Maven: (for what it's worth) I've only glanced at some configurations and they seem overly complicated when I compare them to a Gradle script.

There is one thing Maven does that you can't do with GradleFx (yet). It can pull the right Flex SDK from a Maven repo and build against that. With GradleFx you have to have your SDK's available locally.

How do you get the line height of the text in a Spark Label?

Question

How do you determine the line height (in pixels) of the text in a Spark Label?

Answer  (has 1 votes)

A little something like this:

<fx:Declarations>
    <s:ArrayCollection id="dp">
        <fx:Object title="Panel A" content="content AAAAA" />
        <fx:Object title="Panel B" />
        <fx:Object title="Panel C" />
        <fx:Object title="Panel D" />
    </s:ArrayCollection>
</fx:Declarations>

<s:List dataProvider="{dp}" height="100%">
    <s:itemRenderer>
        <fx:Component>
            <s:ItemRenderer>
                <s:Panel title="{data.title}">
                    <s:Label text="{data.content}" />
                </s:Panel>
            </s:ItemRenderer>
        </fx:Component>
    </s:itemRenderer>
</s:List>

Doesn't matter whether you're in AIR or just Flex.

CI-friendly automated builds for as3/flex projects

Question

Disclaimer: I am relatively unfamiliar with the flash build processes, so some/all of this may be misinformed nonsense. Please feel free to suggest alternative approaches.

We're currently developing a flex web app and our build situation is far from ideal. At present we're (as in individual developers) just building using FlashBuilder and deploying manually. The programmers are currently screaming bloody murder for two reasons, though:

(Note: We're only using FlashBuilder because it was the easiest way to set up a flex project in conjunction with Away3d and get it building / rendering correctly -- it's a stopgap solution).

As a predominately .NET development shop, we're used to doing continuous integration as well as continuous deployment. Ideally, we'd like to get something comparable to this for our flash projects without tying ourselves to a particular IDE.

Requirements:

The build process must be:

We don't mind a touch of duplication or a few manual steps (e.g. tarting up the build scripts if we add a new project via an IDE, or generating one configuration from another if tools exist), but the less duplication / maintenance required the better.

I've read quite a few articles / blog posts and watched some short screencasts, but most of them are very thin on the ground on how the build system sits alongside IDEs. Most articles/screencasts have the same formula: How to create a "Hello World" build using a single file & text editors (no IDE).

I've not seen the topic of multiple libraries/projects etc. being broached, either.

After reading around the issue for a while, I'm considering investigating the following options:

Does anyone have any experience of the above solutions (or others I'm unaware of) and, if so, what do you make of them? Any help / pointers appreciated.

Answer  (accepted and has 2 votes)

There's no really easy way to achieve this. What you can do is this:

Create a custom PopupManager

We create a custom PopupManager class to which we can add some custom functionality. In your case it might for instance be interesting to dispatch an event on the Application, so that we can listen to it from everywhere on the displayList. We'll be extending PopUpManagerImpl which is the default implementation used by Flex.

public class MyPopupManager extends PopUpManagerImpl {

    private static var instance:IPopUpManager;

    static public function getInstance():IPopUpManager 
    {
        if (!instance) instance = new MyPopupManager();
        return instance;
    }

    override public function addPopUp(
        window:IFlexDisplayObject, 
        parent:DisplayObject, 
        modal:Boolean=false, 
        childList:String=null, 
        moduleFactory:IFlexModuleFactory=null):void 
    {
        super.addPopUp(window, parent, modal, childList, moduleFactory);
        var app:IEventDispatcher = 
            IEventDispatcher(FlexGlobals.topLevelApplication);
        app.dispatchEvent(new Event("popupAdded", true));
    }

}

We override the addPopup method to dispatch a bubbling event whenever a popup is shown. Ignore the getInstance() method for now. I'll get back to that later. What you do need to know is that FlashBuilder will not automanage some of your imports because these classes were marked as hidden. Nothing to worry about but you'll have to write the import statements manually for:

import mx.managers.IPopUpManager;
import mx.managers.PopUpManagerImpl;

Tell Flex to use your class instead of the default implementation

This would be fairly easy:

import mx.core.Singleton;
Singleton.registerClass("mx.managers::IPopUpManager", MyPopupManager);

The only problem is that Flex has already registered an implementation and you can't override it, even if you execute this on 'preinitialize'. So we'll have to do it before Flex starts bootstrapping. We'll use a custom preloader for that:

public class RegisteringPreloader extends DownloadProgressBar {

    override public function initialize():void {
        super.initialize();
        Singleton.registerClass("mx.managers::IPopUpManager", MyPopupManager);
    }

}

DownloadProgressBar is the default Flex preloader. We just add the extra registering code. Now don't forget to tell your application to use this preloader:

<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"
               preloader="RegisteringPreloader" >

Now just listen for the event

addEventListener("popupAdded", onPopupAdded);
PopUpManager.addPopUp(new Panel(), this);

Extra info

Now why does MyPopupManager have to have a static getInstance() method? Well that's because that Singleton class we used to register our implementation, expects every class it registers to be a singleton and hence to have a method called 'getInstance'. It will try to call this method and will crash if it doesn't exist. If you don't know what a singleton is, just google. You'll find tons of information.

PS: I actually learnt something new trying to solve this question (thanks for that).

Vertical, Scrollable List of Panels

Question

I'm using Adobe Flex Builder 4.5, and I'd like to create a vertical, scrollable list of panels for an AIR application. How do I do that?

Answer  (accepted and has 1 votes)

Almost all keyboard input is disabled in fullscreen mode. This includes the ctrl key. Adobe has done this for security reasons. Only the escape key is allowed, which closes fullscreen mode.

An example: if you would make a fullscreen application that looks exactly like a default Windows logon screen, you could trick a user into typing in his Windows credentials into your application.

I'm also afraid the short answer to your question is: there's no workaround. (Except perhaps if you would use ExternalInterface and some JavaScript to put the browser in fullscreen mode instead of the Flash application.)

Is there a way to listen for events on the pop up manager class?

Question

I'm trying to detect when pop ups are visible (including tool tips if possible). The reason is that I need to hide or freeze (capture a snapshot) the Stage* components (StageWebView, StageVideo, StageText etc) when pop ups appear.

Answer  (accepted and has 0 votes)

The File class has some static variables that point to local directories:

From the docs:

  • File.applicationStorageDirectory — a storage directory unique to each installed AIR application
  • File.applicationDirectory — the read-only directory where the application is installed (along with any installed assets)
  • File.desktopDirectory — the user's desktop directory
  • File.documentsDirectory — the user's documents directory
  • File.userDirectory — the user directory

Creating a pointer to the file

Usually you'll want to store files like these in File.applicationStorageDirectory. So to create the file do:

File.applicationStorageDirectory.resolvePath("my-config.xml");

Alternatively, you can let the user choose where to store the file by using File#browseForSave(), which will display a native 'save' window to choose the location.

Writing the content

Open a FileStream for the File in 'write' mode and write an XML string to the file.

var fs:FileStream = new FileStream();
fs.open(file, FileMode.WRITE);
fs.writeUTF(myXmlContent);
fs.close();

Flex : Capturing Ctrl Key in full screen chart

Question

I am able to capture Ctrl Key just fine in normal mode using event.ctrlKey
For some reason The flag is not set in fullscreen.

protected function chart_itemClickHandler(event:ChartItemEvent):void {
  if( event.ctrlKey) {
    // do something (not executed in fullscreen mode)
  } else {
    // do something else
  }

Is there any trick to get this flag in fullscreen mode?

Answer  (accepted and has 5 votes)

Don't think of it as evaluating a String. It's still just a chain of properties.

So the practical answer to your question is:

var o:Object = {};
o["array"] = [];   //we do have to insantiate the array first
o["array"][0] = 4;

Storing/Saving XML in local asset folder in AIR

Question

AIR in general seems to be storing the xml file in the path where the app is installed. I am generating an xml and I want to save/store a xml file in local asset folder of AIR application.

Any thoughts on doing this.

Answer  (accepted and has 0 votes)

I just took a look at the code on that line in the TitleBar class and it looked like a bug to me.

override protected function commitProperties():void {
    super.commitProperties();

    if (titleChanged) {
        titleText.text = _title;
        titleChanged = false;   
    }

....

As you can see, it doesn't check whether titleText exists before trying to set its text property, even though titleText is not a required skinpart.

So I checked the Adobe JIRA bug database. It turns that this bug has already been filed and is still unresolved:

TitleBar lists titleText as optional, but throws exception when absent

The simplest workaround that i can think of is to leave the titleText Label where it is and just set its visible and includeInLayout properties to false.

Accessing an element of an array of a dynamic class

Question

I have a dynamic class, which has an array declared normally, before runtime.

Usually, you can dynamically access a variable, whether it has been declared or not with

myClass["variable"] = 4;

however, trying to do this with an array, like so

myClass["array[0]"] = 4;

does not store 4 into the first element of array, and instead stores it into the variable "array[0]".

For instance, after executing the previous code,

trace(myClass.array[0]);

traces undefined, where as

trace(myClass["array[0]"]);

traces 4.

Is there anyway I can access the elements of the array dynamically?

Answer  (has 1 votes)

There are two possible answers to your question.

If the "panel' state has nothing more than what's in the two other states, then the following is all you need:

<s:states>
    <s:State name="portrait" stateGroups="panel" />
    <s:State name="landscape" stateGroups="panel" />
    <s:State name="someOtherState" />
</s:states>

If on the other hand other things are also included in the 'panel' state, then it might look more like this:

<s:states>
    <s:State name="portrait" stateGroups="panel" />
    <s:State name="landscape" stateGroups="panel" />
    <s:State name="justThePanel" stateGroups="panel" />
    <s:State name="someOtherState" />
</s:states>

If you now have

<s:Group id="a" includeIn="portrait" />
<s:Group id="b" includeIn="landscape" />
<s:Group id="c" includeIn="someOtherState" />
<s:Group id="d" includeIn="panel" />
<s:Group id="e" />

then

Flex 4 - How to remove titleText from TitleBar skin?

Question

I want to remove title text from titleBar skin but I get an error if I just comment out. I assume it means it is required skin part?

<!-- title -->
<!--- @copy spark.components.windowClasses.TitleBar#titleText -->
<s:Label id="titleText" minWidth="0" maxDisplayedLines="1" width="100%" />

I tried setting it to text="" and text="random text" but no effect. If I set a value in Main application it works but not for empty string.

Right now it shows applications name presumably from "Main-app.xml" file.

How can I get rid of it? Any help appreciated, this is really bugging me...

Edit 1: TitleBar Skin

<!--- The default skin class for the title bar of the Spark WindowedApplication component
      and Spark Window component when you use Flex chrome.  
      The title bar skin includes the close, minimize, and maximize buttons, the 
      title icon, and the title text.

      <p>The Flex chrome is defined by the SparkChromeWindowedApplicationSkin skin class 
      in the spark.skins.spark package. 
      To use the Flex chrome, set <code>systemChrome</code> to "none" in the application's .xml file,
      and set the <code>skinClass</code> style to spark.skins.spark.SparkChromeWindowedApplicationSkin. </p>

      @langversion 3.0
      @playerversion Flash 10
      @playerversion AIR 1.5
      @productversion Flex 4

      @see spark.components.WindowedApplication
      @see spark.components.Window
      @see spark.skins.spark.SparkChromeWindowedApplicationSkin


    This Skin is based on "TitleBar";
-->
<s:SparkSkin xmlns:fx="http://ns.adobe.com/mxml/2009" xmlns:s="library://ns.adobe.com/flex/spark" 
             xmlns:fb="http://ns.adobe.com/flashbuilder/2009" xmlns:mx="library://ns.adobe.com/flex/mx" 
             minHeight="40" creationComplete="created()" >

    <fx:Metadata>
        [HostComponent("spark.components.windowClasses.TitleBar")]
    </fx:Metadata>

    <fx:Script fb:purpose="styling">


        import mx.core.FlexGlobals;
        import mx.events.StateChangeEvent;

        /* Exclude the titleBar and scroller because they are SparkSkins and we
         * don't want to colorize them twice. */
        static private const exclusions:Array = ["titleBar"];

        override public function get colorizeExclusions():Array
        {
            return exclusions;
        }

        override protected function initializationComplete():void
        {
            useChromeColor = true;
            super.initializationComplete();
        }

        public var ifo:Boolean;

        public function created():void
        {
            this.hostComponent.parentApplication.addEventListener(StateChangeEvent.CURRENT_STATE_CHANGE, buttonToggle);
        }

        override protected function updateDisplayList(unscaledWidth:Number, unscaledHeight:Number):void
        {
            //trace(hostComponent.parentApplication.currentState);
            backgroundRect.radiusX = getStyle("cornerRadius");

            super.updateDisplayList(unscaledWidth, unscaledHeight);
        }

        private function returnButtonHandler(event:MouseEvent):void
        {
            this.hostComponent.parentApplication.currentState = "Home";
        }

        private var lastState:String;

        private function buttonToggle(event:StateChangeEvent):void
        {
            lastState = event.oldState;

            if(event.newState == "Home")
            {
                returnButton.visible = false;
                settingsButton.label = "Settings";
            }
            else if(event.newState == "MoviePage")
            {
                returnButton.visible = true;
                settingsButton.label = "Settings";
            }
            else
            {
                returnButton.visible = false;
                settingsButton.label = "Back";
            }
        }

        private function settingsButtonHandler(event:MouseEvent):void
        {
            if(settingsButton.label == "Settings") // if button label is settings
            {
                hostComponent.parentApplication.currentState = "Settings";
            }
            else // if button label is back
            {
                hostComponent.parentApplication.currentState = lastState; // return to previous state
            }
        }

    </fx:Script>

    <s:states>
        <s:State name="normal" />
        <s:State name="disabled" />
        <s:State name="normalAndMaximized" stateGroups="maximizedGroup" />
        <s:State name="disabledAndMaximized" stateGroups="maximizedGroup" />
    </s:states>

    <!-- fill -->
    <!--- Defines the background color of the title bar. -->
    <s:Rect id="backgroundRect" left="0" right="0" top="0" bottom="0" >
        <s:fill>
            <s:LinearGradient id="bgFill" rotation="90">
                <s:GradientEntry color="0xFFFFFF" />
                <s:GradientEntry color="0xBABABA" />
            </s:LinearGradient>
        </s:fill>
    </s:Rect>

    <!-- title bar content -->
    <s:Group id="titleBar" minHeight="40" width="100%" height="100%" left="3" right="2" >
        <s:layout>
            <s:HorizontalLayout verticalAlign="middle" gap="5" />
        </s:layout>

        <!-- title bar icon -->
        <!--- @copy spark.components.windowClasses.TitleBar#titleIconImage -->
        <s:BitmapImage id="titleIconImage" minWidth="0" fillMode="clip"/>

        <!-- return button -->
        <s:Button id="returnButton" label="Return" click="returnButtonHandler(event)" visible="false" />

        <!-- title -->
        <!--- @copy spark.components.windowClasses.TitleBar#titleText -->
        <s:Label id="titleText" visible="false" includeInLayout="false" minWidth="0" maxDisplayedLines="1" width="100%" /> !!!!!!!! Error if this line is deleted !!!!!!!!!

        <!-- settings / back button -->
        <s:Button id="settingsButton" label="Settings" click="settingsButtonHandler(event)" visible="true" />

        <!-- minimize button -->
        <!--- 
            By default, the button uses the spark.skins.spark.windowChrome.MinimizeButtonSkin class
            to define the skin for the mimimized button.
            @copy spark.components.windowClasses.TitleBar#minimizeButton 
            @see spark.skins.spark.windowChrome.MinimizeButtonSkin 
        -->
        <s:Button id="minimizeButton" verticalCenter="0"
            skinClass="skins.CustomMinimizeButtonSkin" />

        <!-- maximize button -->
        <!--- 
            By default, the button uses the spark.skins.spark.windowChrome.MinimizeButtonSkin class
            to define the skin for the maximized button.
            @copy spark.components.windowClasses.TitleBar#maximizeButton
            @see spark.skins.spark.windowChrome.MaximizeButtonSkin 
        -->
        <s:Button id="maximizeButton" verticalCenter="0"
                  skinClass="skins.CustomMaximizeButtonSkin"
                  skinClass.maximizedGroup="skins.CustomRestoreButtonSkin" />

        <!-- close button -->
        <!---
            By default, the button uses the spark.skins.spark.windowChrome.MinimizeButtonSkin class
            to define the skin for the close button.
            @copy spark.components.windowClasses.TitleBar#closeButton
            @see spark.skins.spark.windowChrome.CloseButtonSkin
        -->
        <s:Button id="closeButton" verticalCenter="0"
            skinClass="skins.CustomCloseButtonSkin" />
        <s:Spacer />

    </s:Group>

</s:SparkSkin>

Application Skin Code Snippet:

<!-- layer 3: title bar + content -->
    <s:Group left="0" right="0" top="0" bottom="0" minHeight="0" minWidth="0" >
        <s:layout>
            <s:VerticalLayout gap="0"/>
        </s:layout>

        <!-- title bar -->
        <s:TitleBar id="titleBar" width="100%" minHeight="40" skinClass="skins.CustomTitleBarSkin" />

        <!-- content -->
        <s:Group id="contentGroup" width="100%" height="100%" minHeight="0" minWidth="0" />

    </s:Group>

    <!-- layer 4: gripper -->
    <!--- @see spark.skins.spark.windowChrome.GripperSkin -->
    <s:Button id="gripper" right="6" bottom="5" tabEnabled="false" 
              skinClass="spark.skins.spark.windowChrome.GripperSkin" /> 

</s:SparkSkin>

Error:

[SWF] Main.swf - 5,439,008 bytes after decompression
TypeError: Error #1009: Cannot access a property or method of a null object reference.
    at spark.components.windowClasses::TitleBar/commitProperties()[E:\dev\4.y\frameworks\projects\airspark\src\spark\components\windowClasses\TitleBar.as:443]
    at mx.core::UIComponent/validateProperties()[E:\dev\4.y\frameworks\projects\framework\src\mx\core\UIComponent.as:8219]
    at mx.managers::LayoutManager/validateProperties()[E:\dev\4.y\frameworks\projects\framework\src\mx\managers\LayoutManager.as:597]
    at mx.managers::LayoutManager/doPhasedInstantiation()[E:\dev\4.y\frameworks\projects\framework\src\mx\managers\LayoutManager.as:783]
    at mx.managers::LayoutManager/doPhasedInstantiationCallback()[E:\dev\4.y\frameworks\projects\framework\src\mx\managers\LayoutManager.as:1180]

Answer  (accepted and has 1 votes)

You have to jump through a few hoops for this one because DropDownList prevents any MouseEvent.CLICK from an object inside an ItemRenderer from being fired.

First things first: you will need a custom event for this to work. One that carries your item or at least its index. e.g.:

public class ItemEvent extends Event {
    public static const REMOVE:String = "itemRemove";

    public var item:MyClass;

    public function ItemEvent(type:String, item:MyClass, 
                              bubbles:Boolean=false, 
                              cancelable:Boolean=false) {
        super(type, bubbles, cancelable);
        this.item = item;
    }

    override public function clone():Event {
        return new ItemEvent(type, item, bubbles, cancelable);
    }

}

Then you create a custom ItemRenderer with a 'delete' Button that will dispatch this event.

<s:ItemRenderer xmlns:fx="http://ns.adobe.com/mxml/2009" 
                xmlns:s="library://ns.adobe.com/flex/spark">

    <fx:Script>
        <![CDATA[
            private function remove():void {
                owner.dispatchEvent(
                    new ItemEvent(ItemEvent.REMOVE, data as MyClass)
                );
            }
        ]]>
    </fx:Script>

    <s:Label id="labelDisplay" verticalCenter="0" left="10" />

    <s:Button verticalCenter="0" right="10" width="16" height="16"
              mouseDown="remove()" />

</s:ItemRenderer>

Important here is that you catch the MOUSE_DOWN event of the Button, since its CLICK event doesn't fire (as mentioned before). The owner property of the ItemRenderer refers to the List it is a child of.

Now the last piece of the puzzle. Here's your DropDownList with custom ItemRenderer:

<s:DropDownList id="myDropDownList" dataProvider="{dp}"
                itemRenderer="MyItemRenderer" />

And here's how you listen for that custom event and remove the selected item:

myDropDownList.addEventListener(ItemEvent.REMOVE, removeSelectedItem);

private function removeSelectedItem(event:ItemEvent):void {
    var items:IList = myDropDownList.dataProvider;
    var index:int = items.getItemIndex(event.item);
    items.removeItemAt(index);
}

Because we caught the MOUSE_DOWN instead of CLICK the myDropDownList.selectedIndex property will still be at the previously selected item (or -1 if none was selected). This is why we needed the custom event, because there was no other way of knowing which is the item you want to remove.

How to create a state that includes other states

Question

I have a mobile app where I have 3 states in it. There is the default portrait and landscape and I would to add a third state that includes the other two.

<s:states>
    <s:State name="portrait"/>
    <s:State name="landscape"/>
    <s:State name="panel" stateGroups="portrait, landscape"/>
</s:states>

In this third state called, "panel", I want to include the portrait and landscape states in it. When I do this I get the following error:

Identifier 'landscape' used for both a state group and a state.

BTW I've been trying to understand stateGroups and I don't think I'm getting it.

UPDATE
Here is more context. I have a container called, "appMenu" that I want to make visible when the user presses the menu key. So I want to create a state for this. Right now only one value that changes and that is the "y" property. Since this is an mobile application the device will be in a portrait or landscape mode (state). I don't want to take the user out of those states only apply this new property to whatever state they were in.

<s:BorderContainer id="appMenu"
                   borderVisible="false"
                   width="100%" 
                   height="120" 
                   y="-120"  
                   y.panelVisible="0" 
                   backgroundColor="0"
                   >
    <s:HGroup right="10" verticalCenter="0">
        <s:Label text="Feedback" 
                 color="#ffffff" 
                 fontSize="18" 
                 fontWeight="bold"/>
    </s:HGroup>
</s:BorderContainer>

Answer  (accepted and has 1 votes)

The Spark GridItemRenderer still has a data property, just as any other ItemRenderer does, so you're fine there.

What you need in addition to that is the column property, which returns a GridColumn instance. This is the same instance you probably defined in mxml when creating the DataGrid, hence it has all its properties. The ones you'll use most are dataField and columnIndex.

For instance:

var value:* = data[column.dataField];
var index:int = data[column.columnIndex];

Create dropdownlist with delete button in this itemrenderer

Question

I works with Flex 4.5 and I like to create a custom dropdownlist. Indeed, I'd like to show in each line on my dropdownlist a label and a delete button. The goal is to delete the line on click to delete button. This look like simple, but I don't found how to do that.

Thanks for helping

Answer  (has 1 votes)

Because gap is a 'property' of the VGroup class, not a style. This property is but a wrapper for the VerticalLayout#gap property.

If you use FlashBuilder, you can see the difference between the two in the suggestion list. A property is represented as a green circle. A style is shown as a blue 'Tetris block' shape.

edit Left is also a property but still it does get applied. The reason for this is that in older releases of the Flex SDK baseline, top, bottom, left, right, horizontalCenter and verticalCenter where implemented as styles. So the reason you can still use them as such is backwards compatibility.

Flex: get column index in custom itemrenderer for spark datagrid

Question

I am trying to use the same custom renderer for all the columns in a spark DataGrid. I need to know the dataField or columnIndex based on which I can change state in my custom itemrenderer.

Earlier in mx:DataGrid, this can be achieved by extending the MXDataGridItemRenderer which implements IDropInListItemRenderer and hence dataGridListData property is available.

But using the spark DataGrid, I am extending the GridItemRenderer which DOES NOT implement the IDropInListItemRenderer and hence unable to access dataGridListData property. I have tried to write an action script class extending GridItemRenderer and implementing dataGridListData but flex throws an error in the set function of this variable.

Can anyone help me in accomplishing this?

// Sample itemRenderer used for mx:DataGrid [Working Code]

<fx:Script>
    <![CDATA[
        import mx.events.FlexEvent;

        import scripts.valueObjects.CellRendererVO;

        private var _cellRenderer:CellRendererVO = new CellRendererVO();
        [Bindable]
        private var _lineColor:uint = 0xFF0000;
        [Bindable]
        private var _lineWidth:int = 5;

        override public function set data(value:Object):void
        {
            //able to access the dataGridListData.dataField variable
            _cellRenderer = (value[dataGridListData.dataField] as CellRendererVO);
            currentState = _cellRenderer.stateName;
        }

        private function connectingLinesState_enterStateHandler(event:FlexEvent):void
        {
        }

        protected function orgChartNodeState_enterStateHandler(event:FlexEvent):void
        {
        }

    ]]>
</fx:Script>

<s:states>

    <s:State name="emptyState" />

    <s:State name="orgChartNodeState" enterState="orgChartNodeState_enterStateHandler(event)"/>

    <s:State name="connectingLinesState" enterState="connectingLinesState_enterStateHandler(event)"/>

</s:states>

<s:HGroup width="100%" height="100%" includeIn="orgChartNodeState"
          horizontalAlign="center" verticalAlign="middle">


</s:HGroup>

<s:HGroup width="100%" height="100%" includeIn="connectingLinesState"
          gap="0" horizontalAlign="center" verticalAlign="middle"
          paddingLeft="0" paddingRight="0" paddingTop="0"
          paddingBottom="0">


</s:HGroup>

// sample spark DataGrid itemRenderer [NOT Working]

package customComponents.myOrgChart { import mx.controls.dataGridClasses.DataGridListData; import mx.controls.listClasses.BaseListData; import mx.controls.listClasses.IDropInListItemRenderer; import mx.controls.listClasses.IListItemRenderer;

import spark.components.gridClasses.GridItemRenderer;

public class TestRenderer extends GridItemRenderer implements IListItemRenderer, IDropInListItemRenderer
{

    private var _listData:BaseListData;

    public function TestRenderer()
    {
        super();
    }

    override public function set data(value:Object):void
    {
        //Flex throws error here.
        //ERROR: TypeError: Error #1009: Cannot access a property or method of a null object reference.
        trace('dataField: ' + DataGridListData(listData).dataField);
    }

    public function get listData():BaseListData
    {
        return _listData;
    }

    public function set listData(value:BaseListData):void
    {
        _listData = value;
    }
}

}

Thanks,

Anji

Answer  (has 2 votes)

You'll have to create a custom sorting function. In that function you'll have to select the numeric values in the Strings and sort on them. In short:

immarray.sort(sortNumeric);

private function sortNumeric(a:String, b:String):int {
    return a.match(/\d+/g)[0] - b.match(/\d+/g)[0];
}

Some explanation: the regular expression \d+ finds the numeric characters in the String. Note that this example is not programmed defensively and assumes that every String is formatted in the same way (e.g. 'imm10').

Flex 4.6 CSS vgroup "gap" ignored

Question

<?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"     
           >
    <fx:Style>    
        @namespace s "library://ns.adobe.com/flex/spark";
        @namespace mx "library://ns.adobe.com/flex/mx";
        s|VGroup {
            gap: 150;
            left: 30;
        }
    </fx:Style>
    <s:VGroup>
        <s:Label text="text1" />
        <s:Label text="text1" />
    </s:VGroup>
</s:Application>

The VGroup is 30 Pixel from left, as assumed (this is my proof that the style is used) But it ignores the given gap. When i feed 'gap="150"' directly into the VGroup-Element, it works. So why is this ignored when coming over css?

thank you for any hint.

cu, Markus

Answer  (accepted and has 3 votes)

No, you can't. And even if you could package it, the data wouldn't really be protected: since an .air package is in essence nothing more than an enhanced .zip archive, anyone could just extract the database from the .air file.

What you have to do is encrypt your database and protect it with a password so that only authorized users can access the database.

There's ample documentation on how to do this. Here's a tutorial from Adobe to get you started: http://www.adobe.com/devnet/air/flex/quickstart/articles/encrypted_database.html

Sort an array composed by alphanumeric strings

Question

I have an array in which the elements have like ID value "imm1", "imm2", "imm3"..."imm10"

the problem is that the sortOn method consider "imm10" lower than "imm2" because it consider 1 and 0 separatly. Then I tryed to write

immarray.sortOn("id", Array.NUMERIC)

but it don't apply the order correctly and I don't know why... maybe because my ID propriety have an alphanumeric value? Then, how I can sort i t correctly?

I want this result:

imm1
imm2
imm3
...
imm10
imm11
imm12
etc... 

Answer  (accepted and has 1 votes)

In my experience the usage of the mx::internal namespace in the Flex SDK usually means something along the lines of: "you can use this functionality, if you know what you're doing, and also we (Adobe, or the Apache community in the future) don't guarantee that this API will never change in future versions of Flex".

So there's no real issue with its usage, unless you're very concerned with backwards compatibility. If you really want to avoid using it, you can always just implement the behavior of skinDestructionPolicy="auto" in your subclass. There's not that much code to write:

    override public function initialize():void {
        addEventListener(Event.ADDED_TO_STAGE, addedToStageHandler);
        addEventListener(Event.REMOVED_FROM_STAGE, removedFromStageHandler);

        super.initialize();
    }

    private function addedToStageHandler(event:Event):void {
        if (skin == null) attachSkin();
    }

    private function removedFromStageHandler(event:Event):void {
        detachSkin();
    }

Note that in the SkinnableComponent class these two event listeners are attached (or not, depending on the policy) in the commitProperties() method. I moved that to the initialize() method because we don't need to check for changes in the skinDestructionPolicy property anymore.

Also note that this solution might cause an error if one did set mx::internal skinDestructionPolicy to "auto" alongside.

How to embed a SQLite DB (*.db file) to the AIR application?

Question

I want to emded SQLite database (*.db file) to the AIR app, like images, mp3 etc. This is to ensure that it was impossible to copy my database for other users.

Answer  (accepted and has 3 votes)

The issue is that within your application the TextInput has focus, but within the HTML page your Flex application does not. So basically the only extra step you need is to give the Flex app focus. There's only one way to achieve this: through JavaScript. And you should do it after the application was loaded.

The guys at Farrata wrote a very good example on how to do this, so I'm just going to point you there: http://flexblog.faratasystems.com/2011/12/15/setting-focus-in-flex-components

Dynamically creating a CheckBox with ActionScript

Question

Here's what I have so far,

<?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"
               creationComplete="init()">
    <fx:Declarations>
        <!-- Place non-visual elements (e.g., services, value objects) here -->
    </fx:Declarations>

    <fx:Script>
        <![CDATA[
            import spark.components.CheckBox;

            private function init():void
            {
                var _cb:spark.components.CheckBox= new spark.components.CheckBox();
                _cb.name = "alsowhatever";
                _cb.y = 40;
                addChild(_cb);

            }
        ]]>
    </fx:Script>

</s:Application>

the page does not display the CheckBox as expected, could someone point out where I have gone wrong. (Flash Builder lists my version of Flex as 4.1)

Answer  (has 3 votes)

You can at any time determine what objects are under the mouse by using the DisplayObjectContainer#getObjectsUnderPoint() method. This function returns an Array of objects that lie under the specified point.

I you use it on the stage, it will return all the objects in the application that are under the point.

stage.getObjectsUnderPoint(new Point(mouseX, mouseY));

I guess that in your case it would suffice to only drill down from the container that holds the two Buttons.

myGroupWithButtons.getObjectsUnderPoint(new Point(mouseX, mouseY));

Note that a Button is itself an object that contains several other DisplayObjects and the function might thus return something like this:

myGroupWithButtons.myBtn.ButtonSkin8, [object Shape], [object Shape]

As you can see, in the case of a Spark Button it even lists the Button's skin rather than the Button itself. It's easy enough to get to the Button from there though.

Spark SkinnableComponent skinDestructionPolicy

Question

As a part of trying to tackle a memory leak in our application, we discovered that for every SkinnableComponent, the skinDestructionPolicy is set to "never" by default.

This means that when using static skin parts, the skin is forever detained in memory.
Furthermore, the override of a partRemoved() in the host component will never be triggered. Hence, event listeners we add in the partAdded() override are not removed, which effectively causes views and skins to be kept in memory.

When doing a lot of view switches this is just not acceptable.

Here is an example of of how we are working around this now:

public class ViewA extends SkinnableComponent
{
    [SkinPart(required = "true")]
    public var labelA:Label;

    [SkinPart(required = "true")]
    public var buttonA:Button;

    public function ViewA()
    {
        super();
        mx_internal::skinDestructionPolicy = 'auto';
    }

    override protected function getCurrentSkinState():String
    {
        return super.getCurrentSkinState();
    }

    override protected function partAdded(partName:String, instance:Object):void
    {
        super.partAdded(partName, instance);

        trace("ViewA::partAdded " + partName);

        if (instance == buttonA)
        {
            buttonA.addEventListener(MouseEvent.CLICK, buttonClickedHandler);
        }
    }

    override protected function partRemoved(partName:String, instance:Object):void
    {


        trace("ViewA::partRemoved " + partName);

        if (instance == buttonA)
        {
            buttonA.removeEventListener(MouseEvent.CLICK, buttonClickedHandler);
        }

        super.partRemoved(partName, instance);
    }

    override public function stylesInitialized():void
    {
        setStyle("skinClass", ViewASkin);
    }
}

However, using the mx::internal way to circumvent this behavior seems rather odd to me. Documentation about this is scarce as well, so any ideas will be very welcome.

Cheers

Answer  (has 2 votes)

The biggest difference: Repeater has been deprecated discontinued. It exists as an mx component in Flex 3 only and there is no Spark equivalent in Flex 4. It is encouraged that you use DataGroup+ItemRenderer instead. The main reason for this is very clearly explained in @www.Flextras.com's answer.

Besides that, IMO for anything but the most basic usage Repeater can be a serious pain. Its paradigm is completely different from all the other Flex components, whereas a DataGroup+ItemRenderer approach is very much in line with the Flex component set.

Bottom line: do not use Repeater. There's nothing you can do with Repeater that you can't do with DataGroup+ItemRenderer. (Unless perhaps you're stuck with Flex 3 for some reason. See Amy's comments for more on this.)

setFocus in Flex

Question

I'm Using following code in flex4 mxml That works fine.

<mx:Button label="Set focus to Username"
            click="focusManager.setFocus(username);" />

How to use the same in Action script I mean creation complete event of an application without using button. That is I have login panel in application While page loads the username field should focused having cursor in it.
Can any one help me?

Answer  (accepted and has 1 votes)

Quick and dirty

You can access the skin of any component and just set its state directly:

subMenu.btnDashboard.skin.currentState = "disabled";

That is however not a very clean way to do it. You are telling a Skin class directly what to do and completely bypassing the host component. Hence the host component has no idea of the changes that were made to its skin.

The proper way

A cleaner way to approach this is to expose a property on the host component and then tell the skin to adjust itself to possible changes by overriding the getCurrentSkinState() method.

You could for instance create a property 'enabled' and then tell the skin to update its state by calling invalidateSkinState() whenever 'enabled' is being set.

public function set enabled(value:Boolean):void {
    _enabled = value;
    invalidateSkinState();
}

Calling invalidateSkinState() will make the skin call getCurrentSkinState() in the next render cycle. This method will then look something like this:

override protected function getCurrentSkinState():String {
    return _enabled ? "normal" : "disabled";
}

Do note that since you are skinning a Button (or a subclass of it) all that I've written here is already baked into that component. So the answer to your question might be as simple as : "just set the 'enabled' property to true.

subMenu.btnDashboard.enabled = true;

ItemRenderer vs Repeater in Flex

Question

Any one of you know about the difference between ItemRenderer and Repeater. Both are behaving the same almost. Any difference is there?

Answer  (accepted and has 1 votes)

Easy enough. The ResultEvent#result property contains the value returned by the remote service. All you need to do is cast it to the right type (since it is an Object by default).

For instance, handling your service method that returns a String:

public function onResult(event:ResultEvent):void {
    var s:String = event.result as String;
}

Same goes for other types:

var a:Array = event.result as Array;

Or even more complex custom classes:

var instance:MyClass = event.result as MyClass;

Note that this last example will only work with AMF remoting; you have to have the same class definition on the client side and on the server side; and you have to let them know of each other's existence by using the [RemoteClass(alias="net.riastar.MyClass")] metadata tag on your AS class definition. How you have to handle this on the server side depends on the language used there.

Setting a skinState of a button in AS3

Question

I want to set (manually) the skinState (for example 'disabled') of a button (that I skinned) in ActionScript.

For example: I have a button skin with hostComponent: components.backend.btnMenuBakComp The button skin has the default button states (up, over, down, ...), but I want to set one of this skinStates in ActionScript.

For example:

subMenu.btnDashboard.currentState = "disabled";

This doesn't work because the state "disabled" is not known in the component (it is only known in the skinState of btnDashboard).

How can I fix this? Is there another solution then load a new skinClass?

Thanks

Answer  (accepted and has 3 votes)

Your gut feeling is correct. ListCollectionView is just a wrapper around any IList that you give it as a source collection. It does not copy the items from the source collection.

This leaves the source collection intact when you filter on it. For example:

var ac:IList = new ArrayCollection([1, 2, 3]);

var l1:ICollectionView = new ListCollectionView(ac);
//filter out only item '1'
l1.filterFunction = function(item:int):Boolean {return item == 1;}
l1.refresh();

var l2:ListCollectionView = new ListCollectionView(ac);
//filter out all items but '1'
l2.filterFunction = function(item:int):Boolean {return item != 1;}
l2.refresh();

trace(ac); //1,2,3
trace(l1); //1
trace(l2); //2,3

Yet at the same time you can still add items to it as if it were the wrapped Ilist itself:

l2.addItem(4);
trace(ac); //1,2,3,4
trace(l1); //1
trace(l2); //2,3,4

Just have a look at the source code of ListCollectionView and you'll see what happens:

public function addItemAt(item:Object, index:int):void
{
    ...
    list.addItemAt(item, listIndex);
}

AsyncToken return basic string?

Question

I'm trying to develop a Flex Mobile / PHP application, and I'm running into some trouble with the AsyncToken... Does it not just return a basic string?

For example... I'm wanting to just return a simple string result from my request - right now, it's going to return a basic output string from the method that's implemented. The backend part works (PHP), I've done all of that... It's this that's giving me some problems:

import mx.rpc.AsyncResponder;
import mx.rpc.events.FaultEvent;
import mx.rpc.events.ResultEvent;
protected function button_clickHandler(event:MouseEvent):void
{
    loginResult.token = user_service.login();
    loginResult.token.addResponder(new AsyncResponder(onResult,onFault));
}

public function onResult(event:ResultEvent, token:Object):void
{
    // what would i do here??
}

public function onFault(event:FaultEvent,token:Object):void
{
    txtResult.text = event.fault.faultDetail;
}

It's pretty straightforward - any suggestions, or recommendations would surely help! Thank you!

Answer  (accepted and has 1 votes)

That's a Spark Application: you should use addElement() instead of addChild(). Use addChild() in mx components only.

Admitted: it's somewhat confusing. Why is there still the public function addChild() if I cannot use it? Well that's because all components extend UIComponent (including the Spark components). So addChild() is only still there for legacy reasons.

Flex ListCollectionView wrapping a list, what is the magic underneath

Question

I am working on an existing project in Flex, and got tripped up for a day trying to figure out how data was getting from one list to another. I think I have figured it out but I'm hoping there are some Flex gurus out there that could shed some light on what is going on.

I'll explain the situation:

There is a datasource lets call its ds, it loads an ArrayCollection (ac) into the model class (m). Then the view class (v) has two ListCollectionViews l1 and l2. Both l1 and l2 have filter functions so half the data get filtered out of l1 and the other half gets filtered out of l2.

Now this all makes sense so far, but if I add data to l1 or l2 it automagically gets added to m.ac. How is this happening? My best guess is that the underpinning data structure of all three lists is the same. But as I have spent so long stuck on this, I would love to know what is going on. Google has not been a lot of help on this one.

[More info] As requested I'll add some more details. Sorry I can't copy and paste what I am working on.

inside model:

      [Bindable] public var ac:ArrayCollection     = null;

inside datasource:

    private function resultHandlerac (event:ResultEvent) : void {
        var ac:ArrayCollection = helperClass.arrayFromResultEvent (event); 
        m.ac = ac;
      }

inside view:

        [Bindable] public var l1:ListCollectionView;
        [Bindable] public var l2:ListCollectionView;

        private function resultHandlerac (ac:ArrayCollection) : void {

            week1Hours = new ListCollectionView(ac);
            week1Hours.filterFunction = function(i:Object) : Boolean { return i.WeekID 
            == 1 && !i.Removed; };

            week2Hours = new ListCollectionView(hoursData);
            week2Hours.filterFunction = function(i:Object) : Boolean { return i.WeekID 
            == 2 && !i.Removed; };

            l1.refresh();
            l2.refresh();
        }

And there is a data grid that displays l1 and l2, every time a feild gets edited, inside the data grid, the three lists update. If more info is required please let me know. I can't put the real code up here as this is not an open source project I am working on.

Answer  (accepted and has 6 votes)

Just use the String#replace() function.

for example:

trace("HELLO there".replace(/e/gi, "a"));
//traces HaLLO thara

The first argument in the replace function is a regular expression. You'll find information about them all over the web. And there's this handy tool from Grant Skinner called Regexr with which you can test your regular expressions ActionScript style.

The part between the two forward slashes (/) is the actual regex.

Note that /e/gi is actually just a shorthand for new RegExp("e", "gi")

as3 replaceAll insensitive

Question

I have this as3 function

public static function StringReplaceAll( source:String, find:String, replacement:String ) : String {
      return source.split( find ).join( replacement );
}

Works fine: any idea how to make it case insenstive ? Regards

Answer  (accepted and has 2 votes)

The Spark List dispatches an 'IndexChangeEvent.CHANGE'. You can listen for this event to know when the selection in the List has changed.

    <s:List id="myList" dataProvider="{myData}" 
            change="handleIndexChange()"
            width="100%" height="100%" fontSize="24" />

That event is only dispatched whenever the selected index actually changes, which means that when you reopen the window a second time an item might still be selected and when you click on that one, no CHANGE event will be fired. To fix this just deselect the selection before you close the window:

        public function close():void {
            myList.selectedIndex = -1;
            PopUpManager.removePopUp(this);
        }

Also make sure to dispatch your event with the selected item before you close the window (and deselect it).

As for your question about the binding warning: you get that message because you didn't mark 'myData' to be bindable. To fix this just use the [Bindable] tag:

[Bindable]
private var myData:ArrayList = new ArrayList();

or skip the binding altogether if you don't need it and just assign the dataprovider to the list in ActionScript:

myList.dataProvider = myData;

Handling mouse click in Flex 4 List to find the selected item (since itemClick is gone)

Question

I have prepared a simplified test case for my question. It will run instantly in your Flash Builder if you put the 2 files below into a project.

I'm trying to display a List of strings and a confirmation checkbox in a popup:

screenshot

In the real application I dispatch a custom event with the string selected in the list, but in the test code below I just call trace(str);

My problem: if I use click event, then the window closes, even if I click at a scrollbar (the !str check below doesn't help, when an item had been selected in previous use). And if I use change event, then the window doesn't close, when I click on the same item as the last time. And the itemClick event seems not to be present in spark.components.List anymore.

Any suggestions please on how to handle this probably frequent problem?

Writing a custom item renderer and having a click event handler for each item seems to be overkill for this case, because I have strings in the list.

Test.mxml: (please click myBtn few times - to see my problems with click and change)

<?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="400" minHeight="300">

    <fx:Script>
        <![CDATA[
            import mx.managers.PopUpManager;

            private var _popup:Popup = new Popup();

            private function showPopup(event:MouseEvent):void {
                PopUpManager.addPopUp(_popup, this, true);
                PopUpManager.centerPopUp(_popup);
            }
        ]]>
    </fx:Script>

    <s:Button id="myBtn" right="5" bottom="5" 
        label="Open window" click="showPopup(event)" />

</s:Application>

Popup.mxml:

<?xml version="1.0" encoding="utf-8"?>
<s:TitleWindow 
    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="240" height="240"
    creationComplete="init(event)"
    close="close()">    

    <fx:Script>
        <![CDATA[
            import mx.collections.ArrayList;
            import mx.controls.Alert;
            import mx.events.FlexEvent;
            import mx.events.CloseEvent;
            import mx.events.ItemClickEvent;
            import mx.managers.PopUpManager;

            private var myData:ArrayList = new ArrayList();

            private function init(event:FlexEvent):void {
                // XXX in the real app data is updated from server
                myData.removeAll();
                for (var i:uint = 1; i <= 10; i++)
                    myData.addItem('Item #' + i);
            }

            public function close(event:TimerEvent=null):void {
                PopUpManager.removePopUp(this);
            }

            private function handleClick(event:MouseEvent):void {
                var str:String = myList.selectedItem as String;
                if (!str)
                    return;

                if (myBox.selected) {
                    Alert.show(
                        'Select ' + str + '?', 
                        null, 
                        mx.controls.Alert.YES | mx.controls.Alert.NO,
                        null,
                        handleConfirm,
                        null,
                        mx.controls.Alert.NO
                    );
                } else {
                    sendEvent();
                }
            }

            private function handleConfirm(event:CloseEvent):void {
                if (event.detail == mx.controls.Alert.YES)
                    sendEvent();
            }

            private function sendEvent():void {
                close();
                // XXX in the real app dispatchEvent() is called
                trace('selected: ' + (myList.selectedItem as String));
            }
        ]]>
    </fx:Script>

    <s:VGroup paddingLeft="20" paddingTop="20" 
            paddingRight="20" paddingBottom="20" gap="20" 
            width="100%" height="100%">
        <s:List id="myList" dataProvider="{myData}" 
            click="handleClick(event)"
            width="100%" height="100%" fontSize="24" />
        <s:CheckBox id="myBox" label="Confirm" />
    </s:VGroup>
</s:TitleWindow>

Also I wonder, why do I get the warning above:

Data binding will not be able to detect assignments to "myData".

Answer  (accepted and has 7 votes)

There are two approaches to this: one uses binding and is easier, the other is more complex but better for performance.

Using binding

Suppose your view class looks like this:

public class MyClass extends SkinnableComponent {
    [Bindable] public var myValue:String;
}

then you can bind to that value in your skin like this:

<s:Skin xmlns:fx="http://ns.adobe.com/mxml/2009" 
        xmlns:s="library://ns.adobe.com/flex/spark">

    <fx:Metadata>
        [HostComponent("MyClass")]
    </fx:Metadata>

   <s:Label id="myLabel" text="{hostComponent.myValue}" />

</s:Skin>

Overriding commitProperties

Assume the same skin without the binding, then you can set the label's text property by using a skinpart and overriding commitProperties in the host component. The skinpart's name must be exactly the same as the id of the component in the skin (in this case 'myLabel').

public class MyClass extends SkinnableComponent {

    [SkinPart(required="true")]
    public var myLabel:Label;

    public var myValue:String;

    override protected function commitProperties():void {
        if (myLabel) myLabel.text = myValue;
        super.commitProperties();
    }
}

Of course you would have to call invalidateProperties() whenever you want to apply the new value (for instance in a setter function for 'myLabel'). Also notice that 'myLabel' no longer needs to be bindable, unless you would want to be able to bind on it externally.


edit: which approach to choose?

I have just answered a question that is closely related to this one in which I elaborate on the pro's and cons of each approach in different situations. You can find it here: Flex: Additional label in ButtonBarButton

Flex : Communicate between the skin and the data model?

Question

How to send to the skin some value which have changed?

Answer  (accepted and has 1 votes)

I have answered a question here just a few days ago that is closely related to this one. It's a bit more abstract, but it should answer yours too. Have a look at Flex : Communicate between the skin and the data model?

As for your additional question about performance improvement: you just have to keep in mind that whenever you use binding, the compiler will generate some event listeners to listen for changes in the data. Of course that's not an issue with a one-off component or even with a bunch of instances, but it may become one if you have a List with thousands of components that all use binding. First of all the garbage collector won't clean these components up so easily when they're no longer needed and secondly - depending on your implementation - thousands of events may be firing at once.

bottom line: you could consider the commitProperties() approach performance tuning, hence you shouldn't consider it until you actually run into a performance issue.

on the other hand from an architectural point of view: that approach allows for a cleaner separation of the component and its skin. With the hostComponent / binding approach you could say the skin knows too much: it has to know about its host component and its properties. While the other one allows you to have a completely 'dumb' skin. So again I tend to use binding with one-off components and commitProperties() with highly reusable ones.

In the end it's all a trade-off (because the 'clean' way is more complex and more work) and it's up to you to make a weighed decision for each particular situation.

Flex: Additional label in ButtonBarButton

Question

I'm trying to extend ButtonBarButton to include an additional label that shows the number of updates for the respective box in a viewstack (which is the tabbar's dataProvider).

I can get the additional label (named indicatorLabel) to read an initial value from data, but I can't get it to update automatically like the actual "label" attribute. My understanding was that you could bind to the data object, but that doesn't appear to be the case.

The box that is used in the viewstack has an attribute called _indicator


[Bindable]
public var _indicator:String;

Which I know is updating properly because I can see it updating in the box (which also has a label bound to it). It appears to just not update the buttonbarbutton.

My buttonbarbutton class has the following (where init() is called in creationComplete


[SkinPart]
public var indicatorLabel:spark.components.Label;

private function init():void
{
 indicatorLabel = data._indicator;
 addEventListener("dataChange", onDataChangeHandler);
}

private function onDataChangeHandler(e:Event):void
{
 trace(e.target.label + ' ' + e.target._indicator);
}

I'm guessing my assumptions for either databinding or the data obj that gets passed to the button are incorrect. Any help is appreciated.

Answer  (accepted and has 2 votes)

at compile time

Actually it's possible to have compile time checking. It just depends how big a leap you're willing to make. For this to work you will have to write your code in haXe instead of ActionScript and have it targeting the Flash platform when compiling. There's a good read on haXe function types on Devboy's blog.

at runtime

If you don't want to go that far, here's how to do it in AS: you'll have to use the describeType() function. Suppose you have a test class like this one:

public class TestClass {    
    public function test(s:String):void {}
}

We can now get information about its functions by writing:

var info:XML = describeType(TestClass);

Somewhere in this XML object there will be a node that looks like this:

<method name="test" declaredBy="net.riastar.test::TestClass" returnType="void">
  <parameter index="1" type="String" optional="false"/>
</method>

There it is! All the information you need to do your checking. But there's one big caveat in this approach: the describeType method is not very efficient. If you have to do this a lot, it will slow down your application. You could use a caching strategy to avoid this though. Or have a look at the as3-commons-reflect project, it will take care of the caching for you.

Flex: passing in function and checking parameters

Question

I am passing in a function to another function which works well. Let's say function "inner" is being passed to function "outer". My problem is that I want function "outer" to be able to check if there are any parameters in function "inner" and their type. I am using the inner function as a callback so it is important that it has one parameter of a specific type. I would like to catch any problems as early as possible so want the "outer" function to check this.

How can I check a function's parameters? Is this possible in Flex?

Thanks

Answer  (accepted and has 1 votes)

Flex components are created in a lazy fashion. That means that any subcomponents will not be created until they are actually needed. And as long as a component has not been added to the displaylist you can be sure its subcomponents will not be needed (you can Google "Flex component life cycle" if you want to get to know more about it).

More concrete for your case

You try to access 'iconDisplay' before the CalloutButton was added to the displaylist, hence the 'iconDisplay' property is 'null'.

Solution

I'm not exactly sure why you want to do this in ActionScript, but here's the fix anyway: you have to listen for FlexEvent.CREATION_COMPLETE. When that event is fired by the CalloutButton, you will be certain that its 'iconDisplay' subcomponent is no longer 'null'.

var editCalloutBtn:CalloutButton = new CalloutButton();
editCalloutBtn.addEventListener(
    FlexEvent.CREATION_COMPLETE, onCalloutButtonReady);
callout_group.addElement(editCalloutBtn);

private function onCalloutButtonReady(event:FlexEvent):void {
    //remove the event listener: we no longer need it
    editCalloutBtn.removeEventListener(    
        FlexEvent.CREATION_COMPLETE, onCalloutButtonReady);

    //no longer null
    trace(editCalloutBtn.iconDisplay); 
}

There can be exceptions to this (when using states for example, or a skin that doesn't have an 'iconDisplay' element), but I'm not going to bother you with that, because they shouldn't happen here.

Unable to set Spark button iconDisplay source. Keep getting null error refernce

Question

Can someone explain what im doing wrong? I'm simply trying to set the icon for a button in a Flex Mobile project using actionscript. I keep getting a null error reference. But i'm 100% sure that is not a bad path. I've used the same path a dozen other times in the app.

var editCalloutBtn:CalloutButton = new CalloutButton;
if(value.type=="reminder")
{
            //this is where the null error happens
        editCalloutBtn.iconDisplay.source="assets/images/reminderIcon_45.png";

}else
{
        editCalloutBtn.iconDisplay.source="assets/images/deadlineIcon_45.png";
}
callout_group.addElement(editCalloutBtn);

For a test, I set the icon using the same path doing everything in mxml, and it works. So it's not the path. But I need to do this with actionscript so I can set the value dynamically.

Any ideas?

Answer  (accepted and has 6 votes)

Since you're a Java guy, you can immediately drop the PHP option: its AMF remoting options are slower than the other 3 and you don't want to learn a new language.

That leaves us with Java, CF, and BlazeDS, which are all basically flavors of Java and performance-wise they can be fairly similar (if used correctly: see further on):

But there's one thing you need to know. Instantiation in CF is terribly expensive - I mean like 500 times slower than Java -, so if you have big lists it's definitely a nono. Unless you use the trick I bumped into a few months ago: instead of instantiating an object you have to create a 'struct' and give it a '__type__' attribute.

example, instead of:

var instance = new path.to.MyClass();
//or
var instance = createObject("component", "path.to.MyClass");

do it like this:

var instance = structNew();
instance["__type__"] = "path.to.MyClass";

and ColdFusion will be just as fast - or maybe even slightly faster - then Java.

I have some benchmarks to back this up. This image is a comparison of how much time it takes to create 50000 instances in some languages. (I was actually trying to tell my boss how crappy CF really is.) And CF8 (not in the chart) is even 100 times slower.

enter image description here

Then I added AMF serialization and the 'typed struct' (as described earlier) to the list and this is the result:

enter image description here

Some column names were lost in the graphic, but the second column from the left is the pure Java option. So with this approach CF9 seems to actually be faster than Java.

Which is the best way to get Data in my Flex Application?

Question

I am new in Flex Development, While creating a new Mobile project it asks me if I want to Connect it to Some Servers and gives me four options `ColdFusion, PHP, Java and blazeDS).

I have worked in java for all the time and not a PHP fellow, I would have simply selected Java and ignored all other. But Since efficiency is an important concern in my current project I dont want to take a chance.

According to you Which one is the best option i.e. ColdFusion, BlazeDS or Java, considering the fact that most of the time I will be storing large binary data in database i.e. Audio / Video files etc.?

Answer  (accepted and has 2 votes)

By putting that Button inside the MySectionComponent tag, you effectively override the value of the 'mxmlChildren' property of the MySectionComponent instance. Hence all the children that were there in the base class disappear and are replaced with just the one Button.

What you should do to fix this issue:

Like this:

<component:MySectionComponent skinClass="MySectionComponentSkin">
    <s:Button id="mybtn"/>
</component:MySectionComponent>

What is different here is that when you use SkinnableContainer, whatever you assign to its 'mxmlChildren' property will be transferred to the 'mxmlChildren' property of the 'contentGroup' in its skin.

If your MySectionComponent is now left with no additional code, you can altogether skip it and use SkinnableContainer directly:

<s:SkinnableContainer skinClass="MySectionComponentSkin">
    <s:Button id="mybtn"/>
</s:SkinnableContainer>

But I see that you have a 'title' in the component, so you will need some additional coding. Your MySectionComponent should look something like this:

public class MySectionComponent extends SkinnableContainer {
    [Bindable] public var title;
}

And now you can access that property from within the skin. First make sure the skin knows its host component:

<s:Skin xmlns:fx="http://ns.adobe.com/mxml/2009" 
        xmlns:s="library://ns.adobe.com/flex/spark">

<fx:Metadata>
    [HostComponent("MySectionComponent")]
</fx:Metadata>

...

Then access the 'title' property like so:

<s:Label text="{hostComponent.title}" />

and remove the 'title' property from your skin class (as you probably copy/pasted it along with the other code).

Flex custom component disappears

Question

I have a problem with a custom component based on a Group. Actually, I want to create a section component (a container with a border and a title). I created a path so that the border doesn't hide the label (title):

<?xml version="1.0" encoding="utf-8"?>
<s:Group 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:Declarations>
        <!-- Placer ici les éléments non visuels (services et objets de valeur, par exemple). -->
    </fx:Declarations>

    <fx:Script>
        <![CDATA[
            [Bindable]
            public var title:String;
        ]]>
    </fx:Script>

    <s:states>
        <s:State name="normal" />
        <s:State name="disabled" />
    </s:states>

    <!-- border --> 
    <s:Path id="border" left="3" right="3" top="5" bottom="5"
            data="M 5 0
            L {this.titleDisplay.left-7} 0
            M {this.titleDisplay.left+this.titleDisplay.width} 0
            L {this.width-5} 0
            C {this.width} 0 {this.width} 0 {this.width} 5
            L {this.width} {this.height-5}
            C {this.width} {this.height} {this.width} {this.height} {this.width-5} {this.height}
            L 5 {this.height}
            C 0 {this.height} 0 {this.height} 0 {this.height-5}
            L 0 5
            C 0 0 0 0 5 0
            ">
        <s:filters>
            <s:GlowFilter alpha="0.5" blurX="10" blurY="10" color="0xffffff"
                          quality="5" strength="6"/>
        </s:filters>
        <s:stroke>     
            <s:SolidColorStroke id="borderStroke" weight="1" color="#ffffff" alpha="0.5"/>
        </s:stroke>
    </s:Path>


    <s:Label id="titleDisplay" maxDisplayedLines="1"
             left="{this.width*0.08}" top="0" bottom="0" minHeight="30"
             verticalAlign="top" textAlign="left" fontWeight="bold"
             text="{title}">
        <s:filters>
            <s:GlowFilter alpha="0.5" blurX="10" blurY="10" color="0xffffff"
                          quality="5" strength="6"/>
        </s:filters>
    </s:Label>

    <!--- @copy spark.components.SkinnableContainer#contentGroup -->
    <s:Group id="contentGroup" width="95%" height="95%" minWidth="0" minHeight="0">
    </s:Group>

</s:Group>

My component looks great with no child. But when I tried something like:

<component:MySectionComponent>
   <s:Button id="mybtn"/>
</component:MySectionComponent>

Nothing else than the button is displayed. I tried changing my Group modified component to a SkinnableContainer but did the same. Furthermore if I add the Button directly into the MySectionComponent contentGroup, it works fine. I just dont know what might be causing this.

Answer  (accepted and has 10 votes)

Yes there is: use the Function.length property. I just checked the docs: it doesn't seem to be mentioned there though.

trace(foo.length); //0
trace(bar.length); //2
trace(jad.length); //2

Notice there are no braces () after the function name. You need a reference of the Function object; adding the braces would execute the function.

I do not know of a way to ascertain that one of the arguments is optional though.

EDIT

What about ...rest parameters?

function foo(...rest) {}
function bar(parameter0, parameter1, ...rest) {}

trace(foo.length); //0
trace(bar.length); //2

This makes sense since there is no way of knowing how many arguments will be passed. Note that within the function body you can know exactly how many arguments were passed, like so:

function foo(...rest) {
    trace(rest.length);
}

Thanks to @felipemaia for pointing that out.

AS3 knowing how many arguments a function takes

Question

Is there a way to know how many arguments an instance of Function can take in Flash? It would also be very useful to know if these arguments are optional or not.

For example :

public function foo() : void                               //would have 0 arguments
public function bar(arg1 : Boolean, arg2 : int) : void     //would have 2 arguments
public function jad(arg1 : Boolean, arg2 : int = 0) : void //would have 2 arguments with 1 being optional

Thanks

Answer  (has 3 votes)

I agree with @Pranav on the methods for logging the clicks, but I totally disagree with how he wants to implement the tracking on the client side.

Solution

If all you need is clicks, then I would just have one click listener on the stage. That way you can handle your click tracking in a class that is completely separate from the rest of your application. And you can do it any way you like. e.g. you could divide the screen into areas and see which areas are most clicked; you could use stage.getObjectsUnderPoint() to find all the objects that were just clicked (usually the topmost object is the one you want, but perhaps you want to log all of them).

Either way, you now have complete liberty in how you choose to track usage and the code is all in one place if you ever need to change anything.

Pass class as constructor's argument

Question

I'm trying to pass my object class as constructor argument. I have something like this:

package myclass {

import flash.display.MovieClip;
import flash.display.BitmapData;
import flash.display.Bitmap;

public class Example extends MovieClip {

    public var  _stageImg:Bitmap;
    public var  _stageData:BitmapData;
    public var  _stageClass:Class;

    private var _stage:Object;

    public function Example(stageClass:Class) {
        _stageClass = stageClass;

    }

    public function createStage():Object {
        _stageData      = new _stageClass(0,0);
        _stageImg       = new Bitmap(_stageData);
        _stage          = addChild(_stageImg);

        return _stage;
    }

}
}

Now, when I try to create my Example:

    import myclass.Example;
    var example:Example = new Example(myObjClass);

I get message, that I'm not passing any variable (Error #1063). Why is that? What is wrong with it?

Answer  (accepted and has 1 votes)

What you need is stage.stageWidth and stage.stageHeight. Of course after Event.ADDED_TO_STAGE, but you already did that.

The 'stage.width' property returns the width of the content on the stage and since there is probably nothing on there yet it returns 0.

SWF tag and stage size in preloader code

Question

I'm trying to get SWFs frame size from preloader code. Please take a look at the example:

[SWF(width='640',height='480',backgroundColor='0xFF00FF',frameRate='60')]
[Frame(factoryClass="MyPreloader")]
public class Main extends Sprite
{
    //My main class, which handles the "Application logic"
}

public class MyPreloader extends MovieClip 
{
    //My preloader code - how to get SWF width from here?
}

When I compile and embed this into HTML page, I get SWF with proper size - 640x480 with pink color. So "[SWF..]" was interpreted correctly. So is "[Frame..]", because preloader code is running.

I can't get SWF size from preloader code (either from the constructor or in Event.ADDED_TO_STAGE event callback method). So far I've tried:

Is there any other way getting SWF size?

Answer  (has 5 votes)

With AIR I can think of a couple of ways to achieve that:

1. with native windows

Set the 'visible' attribute of your main WindowedApplication to 'false'. On 'creationComplete' event spawn a new Window that contains your splash screen. Perform the necessary logic before showing the app. When the bootstrap is done close the splash screen and set the main appliation's 'visible' to 'true'.

2. in one window, using states

Create 2 states (e.g. 'loading' and 'normal'). Set the 'currentState' attribute of your main WindowedApplication to 'loading'. In this state display your splash screen. Perform the necessary logic before showing the app. When the bootstrap is done, set the 'currentState' attribute to 'normal'. In the 'normal' state display your actual application.

3. transparent application

With a transparent AIR application, you could work with states (as in n° 2) and fake windows. Your main application will then be a transparent window that covers the entire screen. You can now position the splash screen and the main view wherever you wish inside this transparent window. Don't worry: you can click through transparent windows so nothing will be blocked.

I could show you some code, but I'd need more specific information about your application.

Edit: example

The easiest solution would be nr 2:

<s:WindowedApplication xmlns:fx="http://ns.adobe.com/mxml/2009"
                       xmlns:s="library://ns.adobe.com/flex/spark"
                       xmlns:v="net.riastar.view"
                       currentState="loading"
                       creationComplete="boot()">

    <fx:Script>
        <![CDATA[
            private function boot():void {
                var bootstrap:Bootstrap = new Bootstrap();
                bootstrap.addEventListener(Event.COMPLETE, showApp);
                bootstrap.boot();
            }

            private function showApp(event:Event):void {
                currentState = 'normal';
            }
        ]]>
    </fx:Script>

    <s:states>
        <s:State name="loading" />
        <s:State name="normal" />
    </s:states> 

    <s:Image source="@Embed('splash.jpg')" includeIn="loading" />
    <v:MainView includeIn="normal" />

</s:WindowedApplication>

example with windows

<s:WindowedApplication xmlns:fx="http://ns.adobe.com/mxml/2009"
                       xmlns:s="library://ns.adobe.com/flex/spark"
                       xmlns:v="net.riastar.view" 
                       creationComplete="showSplash()" 
                       visible="false">

    <fx:Script>
        <![CDATA[
            import mx.events.AIREvent;
            import spark.components.Window;

            private var splash:Window;

            private function showSplash():void {
                splash = new SplashWindow();
                splash.systemChrome = "none";
                splash.type = NativeWindowType.LIGHTWEIGHT;
                splash.addEventListener(AIREvent.WINDOW_COMPLETE, boot);
                splash.open();
            }

            private function boot(event:AIREvent):void {
                var bootstrap:Bootstrap = new Bootstrap();
                bootstrap.addEventListener(Event.COMPLETE, showApp);
                bootstrap.boot();
            }

            private function showApp(event:Event):void {
                callLater(splash.close);

                var mainWin:Window = new MainApplicationWindow();
                mainWin.open();
            }
        ]]>

    </fx:Script>

</s:WindowedApplication>

This one requires more explanation: in your application you'll have to set 'systemchrome' to 'none', 'visible' to 'false' and 'transparent' tot 'true'. You also have to set the 'visible' attribute to 'false'. These settings will effectively hide the main application window. We then sequentially create a window for the splash screen and one for the main view. It is important that the main WindowedApplication stays invisible, because another approach would make that window briefly visible before the splash screen shows up (seems to be a bug).

Adobe AIR - Custom Preloader with Image

Question

Folks,

I have designed an Adobe AIR application. I want to show some preloader on it, before it opens up.

Can anyone guide me with tutorials on preloader aimed for AIR specifically or any already built in ones?

Thanks

Answer  (has 3 votes)

You are passing an instance of your class instead of the definition of the class itself.

In ActionScript it's a bit clunky, but you can get the class definition of an instance like this:

//first get the fully qualified classname, i.e. including the package
var className:String = getQualifiedClassName(myObjInstance);
//then get the class definition for that name
var Klass:Class = getDefinitionByName(className) as Class;
//and finally pass it to your constructor
var example:Example = new Example(Klass);

(note: I named the variable 'Klass' because 'Class' is a reserved keyword)

Looping over elements inside an element in Flex

Question

I have the following function in Flex 4:

protected function initEventHandlers():void
        {
            imageContainer.addEventListener(DragEvent.DRAG_ENTER, acceptDrag);
            imageContainer.addEventListener(DragEvent.DRAG_DROP, handleDrop);

            img_1.addEventListener(MouseEvent.MOUSE_DOWN, handleDrag);
            img_2.addEventListener(MouseEvent.MOUSE_DOWN, handleDrag);
            img_3.addEventListener(MouseEvent.MOUSE_DOWN, handleDrag);
            img_4.addEventListener(MouseEvent.MOUSE_DOWN, handleDrag);
        }

I didn't like the look of this code though. The four images are declared inside my application as follows:

<s:HGroup y="10" width="650" horizontalAlign="center" horizontalCenter="6">
        <s:Image width="80" height="80" source="images/1.jpg" id="img_1" />     
        <s:Image width="80" height="80" source="images/2.jpg" id="img_2" />
        <s:Image width="80" height="80" source="images/3.jpeg" id="img_3" />
        <s:Image width="80" height="80" source="images/4.jpg" id="img_4" />
</s:HGroup>

Isn't there a way to loop over each image in the hgroup and add the eventhandler?

Something like this:

for(image in hgroup) { 
    image.addEventlistener(MouseEvent.MOUSE_DOWN, handleDrag); 

}

 My teacher told me this isn't possible but in case of 10+ images, I can't imagine doing it for every image separately. There has to be a better way to do this, no?

Thanks in advance!

Answer  (accepted and has 4 votes)

Your teacher is wrong!

Give the HGroup an id (e.g. imageGroup).

Then do this:

var numElements:int = imageGroup.numElements;
for (var i:int = 0; i<numElements; i++) {
    var image:Image= imageGroup.getElementAt(i) as Image;
    if (image) image.addEventlistener(MouseEvent.MOUSE_DOWN, handleDrag); 
}

flex not importing SQL based connections?

Question

I'm trying to include a database un flex4 (flashbuilder) project, i don't see data and SQL packages in the import? What might be the reason? Should i add external library?

        import flash.data.SQLConnection;
        import flash.data.SQLStatement;
        import flash.events.SQLErrorEvent;
        import flash.events.SQLEvent;

Description Resource Path Location Type 1172: Definition flash.data:SQLConnection could not be found. EyeVision1.mxml /EyeVision1/src line 28 Flex Problem

Answer  (has 2 votes)

You can use those classes only in an AIR project, not in a web-based Flex project. AIR comes packaged with a SQLite database to which you can connect using these classes.

A Flex web-based application runs on the client not on a server, so if you want to access a database on the server you'll have to use a server side language to do it and pass the results to the Flex app on the client side. If you want to access a local database, well... you can't (except perhaps using HTML5 local storage and ExternalInterface).

Get instances by class name in AS3

Question

I need to get all the instances in my stage according to an especific class name. I'm doing this:

var class_ref:Class = getDefinitionByName('fran.MyOwnClass') as Class;
var element;

for (var i:uint = 0; i < this.parent.numChildren; i++)
{
    element = this.parent.getChildAt(i);
    if (element is class_ref)
    {
        trace('Found element of class fran.MyOwnClass');
    }
}

But I want a better way (more efficiently, without checking all the MCs). Is it possible?

Answer  (has 0 votes)

You could keep a list of all the MC's of a certain type by extending the container class and overriding its addChild(), addChildAt(), removeChild() and removeChildAt() functions.

public class MySprite extends Sprite {

    public var ownClasses:Vector.<MyOwnClass> = new Vector.<MyOwnClass>();

    override public function addChild(child:DisplayObject):DisplayObject {
        addOwnClass(child as MyOwnClass);
        return super.addChild(child);
    }

    override public function addChildAt(child:DisplayObject, index:int):DisplayObject {
        addOwnClass(child as MyOwnClass);
        return super.addChildAt(child, index);
    }

    private function addOwnClass(child:MyOwnClass):void {
        if (child) ownClasses.push(child);
    }

    override public function removeChild(child:DisplayObject):DisplayObject {
        removeOwnClass(child as MyOwnClass);
        return super.removeChild(child);
    }

    override public function removeChildAt(index:int):DisplayObject {
        removeOwnClass(getChildAt(index) as MyOwnClass);
        return super.removeChildAt(index);
    }

    private function removeOwnClass(child:MyOwnClass):void {
        if (child) {
            var i:int = ownClasses.indexOf(child);
            if (i != -1) ownClasses.splice(i, 1);
        }
    }

}

Using this class, every time a child is added, you check whether it's a MyOwnClass and if it is you add it to the ownClasses list. Similar for removing children.

Now you can simply access the list when you need it without looping over the MC's.

public class Main extends MySprite
{
    public function Main()
    {
        addChild(new Sprite());
        addChild(new MyOwnClass());
        trace(ownClasses);
    }
}

This will output [object MyOwnClass]

Getting ahold of the Application to call its method

Question

In my Flex 4.5 application I have a TitleWindow Settings.mxml, which is popped up by the PopUpManager.

Once the user has changed some settings, I not only need to save them to a SharedObject, but also to apply them to the main Application itself - so that the changes are visible to the user immediately.

For example I need to call its method hideApp(somevalue);

The spark.components.Application does not seem to have any static/singleton methods to get ahold of it.

So how do you do it?

And I also wonder how to declare, that an MXML file implements one or several interfaces?

package {
  public interface Hiddable {
    function hideApp(value:Number):void;
  }
}

I'm asking this, because besides the main Application I have a SettingsTest.mxml Application in my project for "unit testing" that particular functionality.

Thank you! Alex

Answer  (has 3 votes)

Yes it does:

FlexGlobals.topLevelApplication

though I would recommend you use events to avoid tight coupling.

As for the question about interfaces: use the attribute implements

<s:Component ... implements="IClassA,IClassB" ... />

How to add RichEditableText of TextArea using only ActionScript

Question

My head is spinning from two days of trying to find an answer to this seemingly simple question.

I'm developing a Flex/AIR application built entirely in ActionScript -- there's no MXML beyond what was originally auto-created.

I need to dynamically generate some kind of editable text-field with high control over formatting. The TLF text fields all seem great, except that I can't get any of them to render on the screen. Due to the nature of the application, they have to be inside a MovieClip, but since I've read that everything must be a descendant of UIComponent, I use UIMovieClip, which is AddChild'ed to the stage.

I'm about to go crazy here, the whole application is in jeopardy over this. I CAN NOT use MXML, and all the 10,000 examples on the internet are MXML. I need to generate these dynamically. I need to generate upwards of 50 fields under one movieclip based on database data. There's no way to hardcode that with MXML. Please don't suggest to change this. The GUI is very specific about this, and it's the right GUI.

In two days of searching, I can't find a single example in ActionScript, only MXML. I've tried everything that smelled like an example.

Is there some obvious general pointer I'm missing? I'll be happy to post code, but it doesn't make sense because I've been through so many examples.

Does anyone have the simplest possible code for creating any kind of TLF text editing field in ActionScript only (zero MXML), which is then added to a MovieClip or UIMovieClip, which is added to the stage of a desktop AIR application?

I will greatly cherish any help here.

Best,

Per

Answer  (has 0 votes)

This should get you started:

//create your TextFlow component
var textFlow:TextFlow = new TextFlow();
var p:ParagraphElement = new ParagraphElement();
var span:SpanElement = new SpanElement();
span.text = "hello world";
p.addChild(span);
textFlow.addChild(p);

//create a Sprite that will contain the text
var textBlock:Sprite = new Sprite();
//create a controller for compositing
var controller:ContainerController = new ContainerController(textBlock);
//set the size of the composition
controller.setCompositionSize(100, 200);
//make the controller control the TextFlow object
textFlow.flowComposer.addController(controller);
//update the composition
textFlow.flowComposer.updateAllControllers();

//add to the stage
addChild(textBlock);

About the size: it is important you use setCompositionSize() instead of the Sprite's width and height properties.

Using addController() you could spread the text over several Sprites. Each Sprite would have its own ContainerController, but all would share the same FlowComposer which would calculate the composition.

warning : using TLF like this can be pretty complicated. Above code is the bare minimum to get things running. I do not know your requirements, but you'll probably hit a few other roadblocks along the way. You have to ask yourself this question: are you really willing to drop all the built-in features of TextArea? It might cost you months of development to get things right, depending on the requirements. You still may want to reconsider your architecture...

Moving spark.components.Application's ControlBar to its bottom

Question

How can Application's ControlBar be moved to its bottom in Flex 4.5 ?

The Adobe doc says only:

By default, the ApplicationSkin class defines the control bar area to appear at the top of the content area of the Application container with a grey background. Create a custom skin to change the default appearance of the control bar.

So I look at spark.skins.spark.ApplicationSkin and there is a controlBarGroup (does it hold the ControlBar contents?), but I don't know how to move it from top to the bottom.

Answer  (accepted and has 1 votes)

First thing you have to do is create a custom skin class. In FlashBuilder (FB) there's an option to create one automatically, but in essence it's just a class like any other.

In FB, right-click somewhere in your project and select 'New > MXML Skin'

enter image description here

Then fill in the wizard form as follows:

enter image description here

Otherwise just create a new .mxml file and copy/paste the code from spark.skins.spark.ApplicationSkin into it.

Then in your application assign the skin class you've just created:

<s:Application ... skinClass="skins.MyApplicationSkin" />

Now let's edit your newly created skin class. This is the part that is of interest to you (I'll cut out some pieces to make it clearer):

<s:Group left="0" right="0" top="0" bottom="0">
    <s:layout>
        <s:VerticalLayout gap="0" horizontalAlign="justify" />
    </s:layout>

    <s:Group id="topGroup" minWidth="0" minHeight="0"
                includeIn="normalWithControlBar, disabledWithControlBar" >

        <!-- some graphic elements here -->

        <s:Group id="controlBarGroup" left="0" right="0" top="1" bottom="1" ...>
            <s:layout>
                <s:HorizontalLayout ... />
            </s:layout>
        </s:Group>
    </s:Group>

    <s:Group id="contentGroup" width="100%" height="100%" ... />

</s:Group>

Almost there. Now all we need to do, is move that 'topGroup' beneath the 'contentGroup'. 'topGroup' contains some graphics + the controlBarGroup. 'contentGroup' is the area where all components will be inserted that you but in you application .mxml file.

<s:Group left="0" right="0" top="0" bottom="0">
    <s:layout>
        <s:VerticalLayout gap="0" horizontalAlign="justify" />
    </s:layout>

    <s:Group id="contentGroup" width="100%" height="100%" ... />

    <s:Group id="topGroup" minWidth="0" minHeight="0"
                includeIn="normalWithControlBar, disabledWithControlBar" >

        <!-- some graphic elements here -->

        <s:Group id="controlBarGroup" left="0" right="0" top="1" bottom="1" ...>
            <s:layout>
                <s:HorizontalLayout ... />
            </s:layout>
        </s:Group>
    </s:Group>

</s:Group>