Width of a group in mx:ViewStack - actionscript-3

I have a simple application:
<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" xmlns:local="*">
<mx:ViewStack width="100%" creationPolicy="all">
<s:NavigatorContent width="100%">
<local:TestGroup width="100%"/>
</s:NavigatorContent>
<s:NavigatorContent width="100%">
<local:TestGroup width="100%"/>
</s:NavigatorContent>
</mx:ViewStack>
</s:Application>
My TestGroup is a bare Spark group. It has creationComplete method, where the width of the group is traced:
<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" creationComplete="group1_creationCompleteHandler(event)">
<fx:Script>
<![CDATA[
import mx.events.FlexEvent;
protected function group1_creationCompleteHandler(event:FlexEvent):void
{
trace("internal group width: " + this.width)
}
]]>
</fx:Script>
</s:Group>
When I run the application, the first TestGroup has width of 1600 (which is about right), but the second one regardless of creationPolicy="all" and width="100%" is 0 (zero).
It turs out that ms:ViewStack doesn't set width for components other than the selected one.
What is the logic behind this behavior?
How can I fix it so that my second group has a real width, and I can get it at the creation complete?

You can listen to change event, that will be fired each time the selected group is changing.
Only the current active group will give you her true width, so you can do someThing like this
<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" xmlns:local="*">
<fx:Script>
<![CDATA[
import mx.events.FlexEvent;
protected function onChange(event:Event):void
{
if(myViewStack.selectedChild){
myViewStack.selectedChild.initMyGroup();
}
}
]]>
</fx:Script>
<mx:ViewStack id="myViewStack" width="100%" creationPolicy="all" change="onChange()">
<s:NavigatorContent width="100%">
<local:TestGroup width="100%"/>
</s:NavigatorContent>
<s:NavigatorContent width="100%">
<local:TestGroup width="100%"/>
</s:NavigatorContent>
</mx:ViewStack>
</s:Application>
<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:Script>
<![CDATA[
import mx.events.FlexEvent;
public function initMyGroup():void
{
trace("internal group width: " + this.width)
}
]]>
</fx:Script>
</s:Group>

The ViewStack is a Multiple-view container. Even though having the creationComplete set to all which is by the way for Single-view containers only, Flex instantiates only the controls that are initially visible for the ViewStack. To achieve your goal, try using other containers aside from ViewStack.
More details can be found here:
http://livedocs.adobe.com/flex/3/html/help.html?content=layoutperformance_05.html

What is the logic behind this behavior?
Because there is no need to render a TestGroup element. If you set creationPlicy for all a flex container will create internal element, but it doesn't mean that the container will set size for the element.
How can I fix it so that my second group has a real width, and I can get it at the creation complete?
Use event updateComplete. Flex dispatches updateComplete events whenever the layout, position, size, or other visual characteristic of the component changes and the component is updated for display. So you will get it when second TestGroup will be selected first time.

Related

Get flex component id using Mouse event action

In flex application how to get the ID of specific display component using mouse event. For example if I want to get the ID of a button it should be displayed when I click the button
do it with event.currentTarget.id like 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">
<fx:Script>
<![CDATA[
import mx.controls.Alert;
protected function niceButton_clickHandler(event:MouseEvent):void
{
Alert.show(" the button id is: "+event.currentTarget.id)
}
]]>
</fx:Script>
<fx:Declarations>
<!-- Place non-visual elements (e.g., services, value objects) here -->
</fx:Declarations>
<s:HGroup width="100%" height="100%" verticalAlign="middle" horizontalAlign="center">
<s:Button id="niceButton" label="click me" click="niceButton_clickHandler(event)" />
</s:HGroup>
</s:Application>

Disable alternatingItemColor property for AdvancedDataGrid if the rows are empty

I have a custom AdvancedDataGrid and we use alternatingItemColors property which shows two different colors for rows of the AdvancedDataGrid. Now sometimes the datagrid has 15 rows but only 5 would have data and we want only first 5 rows to display alternating colors and rest of the rows should only display one color. Has anyone done this in past and if someone can please explain how to do this would be really appreciated.
Thanks in advance.
You have to override the Datagrid and override drawRowBackground method, if the rowInd is more than the number of rows then set the default color. See the code snippet mentioned given below -
public class CustomDataGrid extends AdvancedDataGrid
{
protected override function drawRowBackground(s:Sprite, rowIndex:int, y:Number, height:Number, color:uint, dataIndex:int):void{
var XMLdata:XML=rowNumberToData(dataIndex) as XML;
if(XMLdata!=null){
if(XMLdata.attribute(Constants.col) != undefined && XMLdata.attribute(Constants.col) != ""){
color=XMLdata.attribute(Constants.col);
}else{
color=0xFFFFFF;
}
}
super.drawRowBackground(s,rowIndex,y,height,color,dataIndex);
}
}
Either set rowCount to the actual row count when you have fewer rows than the height allows for, or override drawRowBackground.
Try by using Item renderer for your ADG: -
<?xml version="1.0" encoding="utf-8"?>
<s:Application xmlns:fx="http://ns.adobe.com/mxml/2009"
xmlns:s="library://ns.adobe.com/flex/spark"
xmlns:mx="library://ns.adobe.com/flex/mx" minWidth="955" minHeight="600"
>
<fx:Declarations>
<!-- Place non-visual elements (e.g., services, value objects) here -->
</fx:Declarations>
<fx:Script>
<![CDATA[
import mx.collections.ArrayCollection;
import mx.events.FlexEvent;
[Bindable]
private var dpHierarchy:ArrayCollection= new ArrayCollection([
{name:"A", region: "Arizona"},
{name:"B", region: "Arizona"},
{name:"C", region: "California"},
{name:"D", region: "California"}
]);
]]>
</fx:Script>
<mx:AdvancedDataGrid id="myADG"
width="500" height="500"
paddingBottom="0" paddingLeft="0" paddingRight="0" paddingTop="0"
dataProvider="{dpHierarchy}"
itemRenderer="DrawAlternateRowColor">
<mx:columns>
<mx:AdvancedDataGridColumn dataField="name" headerText="Name" />
<mx:AdvancedDataGridColumn dataField="region" headerText="Region" />
</mx:columns>
</mx:AdvancedDataGrid>
</s:Application>
//ItemRenderer name: - DrawAlternateRowColor -- you can use the same concept with you CADG.
<?xml version="1.0" encoding="utf-8"?>
<s:MXAdvancedDataGridItemRenderer xmlns:fx="http://ns.adobe.com/mxml/2009"
xmlns:s="library://ns.adobe.com/flex/spark"
xmlns:mx="library://ns.adobe.com/flex/mx"
focusEnabled="true" alternatingItemColors="[#0000FF, #FF0000]"
width="100%" height="100%">
<s:Label id="lblData" verticalAlign="middle" text="{listData.label}" />
</s:MXAdvancedDataGridItemRenderer>

Fade effect being applied to the adjacent ItemRenderer

I am applying s:Fade effect on s:ItemRenderer on mouseOver event. The fade effect ends fine, but during its execution, it is applied only on half of the ItemRenderer object, plus half of the adjacent (right) ItemRenderer.
ItemRenderer objects are inside a s:List which uses a HorizontalLayout.
Here is the code for the ItemRenderer called FilterTagRenderer:
<?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="false"
mouseOver="{fadeIn.play()}"
mouseOut="{alpha = 0.6}"
alpha="0.6">
<fx:Declarations>
<s:Fade id="fadeIn" alphaTo="1" duration="500" target="{this}"/>
</fx:Declarations>
<s:Label id="lblFilterName" text="{data}" paddingBottom="5" fontWeight="bold" fontSize="14"/>
</s:ItemRenderer>
Here is the code for List:
<s:List id="filterValuesList" width="{this.width}" borderVisible="false"
itemRenderer="view.FilterTagRenderer">
<s:layout>
<s:HorizontalLayout id="flowLayout" gap="6"/>
</s:layout>
</s:List>
I am using Flex SDK 4.0.
Does anyone know if this is a bug in flex or am I doing something wrong?
Thanks
You're doing something a little bit wrong, in that with Spark components you should let the state change run th effect, rather than trying to run it yourself. However, effects under the hood are just a filter on a single DisplayObject, so I'm not sure how you can get an effect that's partially on two different objects. Your renderers are probably just not where you think they are. What happens if you use one of the layouts that came with Flex, such as TileLayout?
Seems like a bug.
Steps to reproduce: simply compile and run the following two files, and then move the mouse over to any word.
Application file (FadeBug.mxml):
<?xml version="1.0" encoding="utf-8"?>
<s:Application xmlns:fx="http://ns.adobe.com/mxml/2009"
xmlns:s="library://ns.adobe.com/flex/spark"
xmlns:mx="library://ns.adobe.com/flex/mx" minWidth="955" minHeight="600">
<fx:Script>
<![CDATA[
import mx.collections.ArrayCollection;
]]>
</fx:Script>
<s:List dataProvider="{new ArrayCollection('The quick brown fox jumped over the lazy dog'.split(' '))}"
itemRenderer="BuggyItemRenderer" >
<s:layout>
<s:HorizontalLayout gap="6"/>
</s:layout>
</s:List>
</s:Application>
BuggyItemRenderer.mxml:
<?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="false"
alpha="0.4"
mouseOver="{fadeEffect.play()}"
mouseOut="itemrenderer1_mouseOutHandler(event)">
<fx:Script>
<![CDATA[
protected function itemrenderer1_mouseOutHandler(event:MouseEvent):void
{
if (fadeEffect.isPlaying) {
fadeEffect.stop();
}
this.alpha = 0.4;
}
]]>
</fx:Script>
<fx:Declarations>
<s:Fade id="fadeEffect" target="{this}" alphaFrom="0.4" alphaTo="1"/>
</fx:Declarations>
<s:Label text="{data}" fontSize="25" fontWeight="bold"/>
</s:ItemRenderer>

Adding a border to a group in run time in flex

i am trying to make a group of spark type in flex at runtime.i am making a couple of buttons as children of this group in runtime. i want to add border to all group. however when i use border container it hides all other children and the stuff in group container and only shows the border container screen. How can i add border to group.
Note that i am adding the border container as a child of group container in run time.
best regards
You can add a s:Rect child at particular index acting as a border.
<?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">
<fx:Script>
<![CDATA[
import mx.graphics.SolidColorStroke;
import spark.primitives.Rect;
protected function addNewBorderButtonClick(event:MouseEvent):void
{
var borderRect:Rect = new Rect();
var solidStroke:SolidColorStroke = new SolidColorStroke(0, 3);
borderRect.stroke = solidStroke;
borderRect.percentWidth = borderRect.percentHeight = 100;
targetGroup.addElementAt(borderRect, 0);
}
]]>
</fx:Script>
<fx:Declarations>
</fx:Declarations>
<s:Group id="targetGroup"
width="100" height="100"
horizontalCenter="0" verticalCenter="0">
<!-- some visual elements here -->
<s:Button id="addNewBorderButton"
label="Add Border"
horizontalCenter="0" verticalCenter="0"
click="addNewBorderButtonClick(event)" />
</s:Group>
</s:Application>
Hope this helps,
Blaze

pass data from popup to parent

I have a parent w/ a popup child. When parent loads, I have to call a function within the popup without showing the popup (thus, I load "pupLove" but don't include it in layout)....I then pass this data to the parent. When the user manually clicks another button to open the popup, the same function is called & data passed to the parent. However, I am not able to pass dg.length to the parent. I believe the root problem is that I am loading "pupLove" & thus the parents are getting confused.....I'm guessing if I get rid of "pupLove" I can pass the data correctly but will need to call the child's function at creationComplete of the parent....how do I do that?
Here's my parent:
<?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"
backgroundColor="green" width="50%" height="100%"
xmlns:local="*"
>
<fx:Script>
<![CDATA[
import pup;
import mx.managers.PopUpManager;
public function showPup(evt:MouseEvent):void {
var ttlWndw:pup = PopUpManager.createPopUp(this, pup, true) as pup;
PopUpManager.centerPopUp(ttlWndw);
}
]]>
</fx:Script>
<mx:VBox>
<local:pup id="pupLove" visible="false" includeInLayout="false" />
<s:Button click="showPup(event);" label="launch Pup" />
<mx:Text id="Ptest" color="black" text="from Parent:{pupLove.dg.length}" />
</mx:VBox>
</s:Application>
And a popup child called 'pup.mxml':
<?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" width="400" height="300">
<fx:Script>
<![CDATA[
public function init():void{
// send php call
}
import mx.events.CloseEvent;
import mx.managers.PopUpManager;
private function removePup(evt:Event):void {
PopUpManager.removePopUp(this);
}
]]>
</fx:Script>
<fx:Declarations>
<s:ArrayCollection id="dg">
</s:ArrayCollection>
</fx:Declarations>
<s:TitleWindow width="100%" height="100%" close="removePup(event)">
<mx:VBox>
<mx:Text id="test" color="red" text="from Child:{dg.length}" />
<s:Button label="add Items" click="dg.addItem({id:'cat'})" />
</mx:VBox>
</s:TitleWindow>
</s:Group>
UPDATE: I guess my question can be more easily stated as: "is there a way to call a child's function from the parent without actually loading the child?"
Well, if in your child's function, you don't need to access any of its UI component, then you could instanciate the child in the parent view and call the method.
When you need to display the popup afterwhile, use the PopupManager addPopup method with this existing instance instead of using createPopup