I have created a Viewstack and using a Tile component and repeating LinkButtons I was able to make a multi column navigation with the viewstack as the dataprovider. My question is can this be done better? My code is below and I am wondering if I took the long way around this approach.
<?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">
<s:layout>
<s:BasicLayout />
</s:layout>
<fx:Script>
<![CDATA[
import mx.controls.Alert;
private var _listItem:Object;
private var n:int=0;
public function get listItem():Object
{
return this._listItem;
}
public function set listItem(listItem:Object):void
{
try{n++;
this.changeSelection(this._listItem);
}catch(e:Error){}
if(n==1 || n > this.viewStack.length){
this._listItem = listItem;
this.changeSelection(listItem);
}
}
private function setSelection(obj:Object):void{
this.viewStack.selectedIndex = this.viewStack.getChildIndex(this.viewStack.getChildByName(obj.target.getRepeaterItem().name));
this.listItem = obj.target;
}
private function checkSelection(obj:Object):void{
if(obj.target.getRepeaterItem() == this.viewStack.selectedChild){
if(this.listItem != obj.target){
this.listItem = obj.target;
}
}
}
private function changeSelection(obj:Object):void{
if(obj.getRepeaterItem() == this.viewStack.selectedChild){
obj.setStyle("color","#000000");
}else{
obj.setStyle("color","#999999");
}
}
]]>
</fx:Script>
<mx:Tile id="tiles" horizontalGap="20" verticalGap="0" y="210" direction="vertical">
<mx:Repeater id="masterList" dataProvider="{viewStack}">
<mx:LinkButton
id="btn"
label="{masterList.currentItem.label}"
click="this.setSelection(event)"
color="#999999"
creationComplete="checkSelection(event);" />
</mx:Repeater>
</mx:Tile>
<mx:ViewStack id="viewStack" height="200" width="300" backgroundColor="#000000" >
<mx:VBox id="vb1" backgroundColor="#FF0000" label="Screen One"/>
<mx:VBox id="vb2" backgroundColor="#00FF00" label="Screen Two"/>
<mx:VBox id="vb3" backgroundColor="#0000FF" label="Screen Three"/>
<mx:VBox id="vb4" backgroundColor="#00FFFF" label="Screen Four"/>
</mx:ViewStack>
</s:Application>
Looks to me like you've got navigation links that expose different and that those links change color based on which one is selected. Assuming that's the case, it sounds an awful lot like a tab-based navigation model. My approach would be to use the spark TabBar and skin the tabs to look like links. That way you can get rid of most of your code and let the tab skin handle changing the colors based on their current state. Also, you wouldn't need any of the code you have for changing the view stack since the TabBar would handle that for you. Hope that helps.
Related
I got a Datagrid in my Flex application.
I need to make appear a context menu when the header row is right-clicked.
The latter context menu must not appear when the rest of the datagrid items (the ones containing data) are clicked.
Edit: the application runs in AIR environment, so i got no flash-player troubles
In flex, and more generally in flash, there is no way to catch the the right click event.
I'm not sure about the right mouse click, cos flex apps run in flash player, and right click brings up its menu.
The best bet would be to use headerRelease event on your DatagRid. In your event handler you can then create your menu (maybe in a popup or some hovering panel?) and then do what you need to do there.
Read more about it here
edit:
Maybe you could use a contextMenu class, and attach it to your dataGrid.contextMenu?
Below code may help you: -
I have created sample in which i have added only one ITEM. You can convert it and change logic as per requirement. My idea is to provide one of the base logic. You may gey better solution but this can work for you.
<?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>
<s:layout>
<s:VerticalLayout/>
</s:layout>
<mx:DataGrid id="myDG" width="350">
<mx:dataProvider>
<mx:ArrayCollection>
<mx:source>
<fx:Object Artist="" Price="11.99"
Album="Slanted and Enchanted" />
<fx:Object Artist=""
Album="Brighten the Corners" Price="11.99" />
</mx:source>
</mx:ArrayCollection>
</mx:dataProvider>
<mx:columns>
<mx:DataGridColumn dataField="Artist" headerRenderer="StackLabelRenderer"/>
<mx:DataGridColumn dataField="Album" headerRenderer="StackLabelRenderer"/>
<mx:DataGridColumn id="price" dataField="Price" headerRenderer="StackLabelRenderer"/>
</mx:columns>
</mx:DataGrid>
</s:Application>
StackLabelRenderer.mxml
<?xml version="1.0" encoding="utf-8"?>
<mx:Label xmlns:fx="http://ns.adobe.com/mxml/2009"
xmlns:s="library://ns.adobe.com/flex/spark"
xmlns:mx="library://ns.adobe.com/flex/mx"
click="dispatchClickEvent()">
<fx:Script>
<![CDATA[
import mx.controls.DataGrid;
import mx.controls.dataGridClasses.DataGridColumn;
import mx.controls.dataGridClasses.DataGridListData;
import mx.core.mx_internal;
private function dispatchClickEvent():void
{
trace("Item Clicked")
}
import mx.controls.Alert;
[Bindable]
private var cm:ContextMenu;
override protected function createChildren():void
{
cm = new ContextMenu();
cm.hideBuiltInItems();
cm.addEventListener(ContextMenuEvent.MENU_SELECT, contextMenu_menuSelect);
this.contextMenu = cm;
}
private function contextMenu_menuSelect(evt:ContextMenuEvent):void {
//condition to check length of column data length
var allNull:Boolean=true;
var columnName:String = DataGridColumn(data).headerText;
for each(var o:Object in DataGrid(owner).dataProvider) {
if(o[columnName] != "") {
allNull=false;
break;
}
}
if(!allNull)
{
var cmi:ContextMenuItem = new ContextMenuItem("First Element...", true);
cmi.addEventListener(ContextMenuEvent.MENU_ITEM_SELECT, contextMenuItem_menuItemSelect);
cm.customItems = [cmi];
}
}
private function contextMenuItem_menuItemSelect(evt:ContextMenuEvent):void {
}
]]>
</fx:Script>
</mx:Label>
I have a spark List,its item renderer is a panel,and in the panel there are some components such as Textinput,now I want to drag and drop a panel within the List,how can I do that,could you pls show me the code,thanks.
The list in flex has a default drag and drop functionality. So basically all you need to do is to set 3 properties to true to your list:
dragMoveEnabled, dragEnabled and dropEnabled. So your list if you add it from mxml will look like this:
<s:List dataProvider="{yourDataProvider}" dragMoveEnabled="true" dragEnabled="true" dropEnabled="true" />
For more details about these 3 properties you can check the spark list documentation:
http://help.adobe.com/en_US/FlashPlatform/reference/actionscript/3/spark/components/List.html#dragMoveEnabled
thanks for your help.Now I catch an error while draging the itemRenderer(my flex sdk is 4.5.1).
My list 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"
width="100%" height="100%">
<fx:Script>
<![CDATA[
import mx.events.CloseEvent;
override public function set data(value:Object ) : void{
super.data = value;
}
protected function closeHandler(event:CloseEvent):void
{
//ToDo
}
]]>
</fx:Script>
<s:TitleWindow x="0" y="0" title="{data.label}"
width="100%" height="100%" creationPolicy="all"
skinClass="skin.titleWindowSkin"
close="closeHandler(event)">
<s:Label text="{data.value}"/>
<s:TextInput x="123" y="58" text="#{data.value}"
focusIn="parentDocument.owner.dragEnabled=false"
focusOut="parentDocument.owner.dragEnabled=true"/>
</s:TitleWindow>
</s:ItemRenderer>
While draging,catch an error like:
Error: Skin for DragProxy261.ListItemDragProxy260.DspDesktopItemRenderer262._DspDesktopItemRenderer_TitleWindow1.titleWindowSkin264.Group265.contents._titleWindowSkin_Group5.contentGroup._DspDesktopItemRenderer_TextInput1 cannot be found.
at spark.components.supportClasses::SkinnableComponent/attachSkin()[E:\dev\4.5.1\frameworks\projects\spark\src\spark\components\supportClasses\SkinnableComponent.as:698]
I am using a the spark tabbar and gave a view stack as dataprovider.....in the view stack there are n elements ...and each element has a panel....
my code would be some thing like this....
<s:tabbar dataprovider = {viewstck-id} height="100%" width="100%"/>
<viewstack id="viewstck-id">
<navigatorContent >
<s:panel title="title - 1"/>
</navigatorContent >
<navigatorContent >
<s:panel title="title - 2"/>
</navigatorContent >\
<navigatorContent >
<s:panel title="title - 3"/>
</navigatorContent >
My requirement is something like this......initially the panel of the select tab should show its own title..suppose if we are on tab-1 the title should be title-1 ...but when we roll over our mouse on tab-2 the title of the panel in tab-1 should be changed to tittle-2 and if the mouse is on tab3 the title of the panel in tab-1 should be changed to tittle-3 and on roll out it should be changed to selected tab's panel's title , i.e. title-1....and in similar way it should work for all the tabs.....
So is there any way to get the get the rollOverIndex of the tab Or some one please provide me a solution.
--
Thanks
Red
Well, my Idea is to use ItemRenderer subclass to handle roll_over event and get item index. By default, TabBar item renderer is ButtonBarButton class with TabBarButtonSkin skin. and ButtonBarButton class has itemIndex property. Let's do it:
---> code for MyButtonBarItemRenderer.mxml
<?xml version="1.0" encoding="utf-8"?>
<s:ButtonBarButton 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="creationCompleteHandler(event)"
skinClass="spark.skins.spark.TabBarButtonSkin"
>
<fx:Script>
<![CDATA[
import events.MyTabBarEvent;
import mx.events.FlexEvent;
protected function creationCompleteHandler(event:FlexEvent):void
{
this.addEventListener(MouseEvent.ROLL_OVER, rollOverHandler);
}
private function rollOverHandler(e:MouseEvent) : void
{
var tbe:MyTabBarEvent = new MyTabBarEvent(MyTabBarEvent.ITEM_ROLL_OVER, true);
tbe.itemIndex = this.itemIndex;
dispatchEvent(tbe);
}
]]>
</fx:Script>
</s:ButtonBarButton>
Here we are using custom event with itemIndex property:
---> code for MyTabBarEvent.as placed in 'events' package
package events
{
import flash.events.Event;
public class MyTabBarEvent extends Event
{
public static const ITEM_ROLL_OVER:String = "MyTabBarEvent.ItemRollOver";
public var itemIndex:int;
public function MyTabBarEvent(type:String, bubbles:Boolean=false, cancelable:Boolean=false)
{
super(type, bubbles, cancelable);
}
}
}
All we have to do now is handle our custom event in our application:
---> code for application
<?xml version="1.0" encoding="utf-8"?>
<s:Application xmlns:fx="http://ns.adobe.com/mxml/2009"
xmlns:s="library://ns.adobe.com/flex/spark"
xmlns:mx="library://ns.adobe.com/flex/mx" minWidth="955" minHeight="600"
creationComplete="creationCompleteHandler(event)"
>
<fx:Declarations>
<!-- Place non-visual elements (e.g., services, value objects) here -->
</fx:Declarations>
<fx:Script>
<![CDATA[
import events.MyTabBarEvent;
import mx.events.FlexEvent;
protected function creationCompleteHandler(event:FlexEvent):void
{
tabBar.addEventListener(MyTabBarEvent.ITEM_ROLL_OVER, itemRollOverHandler);
}
protected function itemRollOverHandler(e:MyTabBarEvent) : void
{
trace ("Item " + e.itemIndex + " roll over event handled");
tabBar.selectedIndex = e.itemIndex;
}
]]>
</fx:Script>
<s:VGroup>
<s:TabBar id="tabBar" dataProvider="{viewstckId}" width="100%" itemRenderer="MyButtonBarItemRenderer"/>
<mx:ViewStack id="viewstckId">
<s:NavigatorContent label="Title 1">
<s:Panel title="title - 1"/>
</s:NavigatorContent >
<s:NavigatorContent label="Title 2">
<s:Panel title="title - 2"/>
</s:NavigatorContent>
<s:NavigatorContent label="Title 3">
<s:Panel title="title - 3"/>
</s:NavigatorContent>
</mx:ViewStack>
</s:VGroup>
</s:Application>
With a Spark TabBar, you could try adding an event listener on MouseEvent.MOUSE_OVER and then checking event.target.label to get the tab name and event.target.itemIndex for the index of the tab that the mouse is hovering over.
Is there an easy way to make a parent container (eg Group) resize when it's children resize?
Below is a little example app. When I put the 200x200 'food' in the 'stomach' the stomach & it's containing 100x100 'body' should resize to contain the food.
Any ideas?
(from this gist http://gist.github.com/301292)
<?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/halo"
minWidth="1024"
minHeight="768"
creationComplete="application1_creationCompleteHandler(event)">
<fx:Script>
<![CDATA[
import mx.events.FlexEvent;
protected function application1_creationCompleteHandler(event:FlexEvent):void {
}
protected function eatFoodTrigger_clickHandler(event:MouseEvent):void {
var food:Border = new Border();
food.setStyle('backgroundColor', 0x15DCA9);
food.width = 200;
food.height = 200;
stomach.addElement(food);
}
]]>
</fx:Script>
<s:Group verticalCenter="0" horizontalCenter="0">
<s:layout>
<s:VerticalLayout horizontalAlign="center" />
</s:layout>
<s:Label fontSize="24" text="The 100x100 pink/brown body has a stomach inside it.
Press eat and the stomach gets 200x200 'food' added to it.
I want the body and the stomach to expand to fit the food." width="200">
</s:Label>
<s:Border id="body"
backgroundColor="0x333333"
minWidth="100"
minHeight="100"
borderColor="0xFF4466"
borderWeight="5">
<s:Group id="stomach">
</s:Group>
</s:Border>
<s:Button id="eatFoodTrigger" click="eatFoodTrigger_clickHandler(event)" label="eat" />
</s:Group>
</s:Application>
Ok so it was a bug in the flex 4 sdk, and it's been fixed. Awesome.
From: http://forums.adobe.com/thread/575252
Your example works for me in a recent
build. Perhaps it was a bug in an old
build. Try one of the new nightly
builds:
http://opensource.adobe.com/wiki/display/flexsdk/DownloadFlex4
-Ryan
Obviously, this is a bit too late, but you could have overriden the addElementAt-method and added some functionality for resizing there. Below, you can see how addElementAdd() should/could be overridden.
//This would be placed in a custom component that extends Group. Your stomach would be this component.
override public function addElementAt(element:IVisualElement, index:int):IVisualElement
{
super.addElementAt(element, index);
ChangeWatcher.watch(element, "width", function():void{ resizeHandler(element) });
ChangeWatcher.watch(element, "height", function():void{ resizeHandler(element) });
}
private function resizeHandler(el:IVisualElement):void
{
var element:DisplayObject = el as DisplayObject;
//Rest of the resizing code.
}
I know this worked for flex3 and Canvas, so it should also work with flex4 and Group.
i need your help about below purposes.
problem-1:In php we can easily move one page to another and easily use different type of function from those pages.In flex3 how i can use different type of .mxml pages like php. Please guide me with tutorials.It will really helpful for me.
problem-2: In same page some content dynamically updated its resource by done one task.How can i do that please guide me.
Rather than treating your Flex application as a series of pages, you may want to consider an all-in-one SWF instead. This greatly reduces navigation time, at the cost of a longer initial download. You can switch among different views using tab pages or view stacks. As far as keeping your functions for each page separate, you can do this by implementing each logical "page" as a separate MXML component. Your top-level application MXML would look something like this:
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml"
xmlns:my="com.mycompany.myapp"
>
<mx:ViewStack id="pageViewStack" width="100%" height="100%">
<my:MyComponent1 width="100%" height="100%"/>
<my:MyComponent2 width="100%" height="100%"/>
</mx:ViewStack>
</mx:Application>
For your second problem I have 2 files
imageResize.mxml
<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" layout="absolute" viewSourceURL="srcview/index.html">
<mx:Script>
<![CDATA[
import mx.collections.ArrayCollection;
private var _imageHolderWidth:Number = 500;
private var _imageHolderHeight:Number = 500;
[Bindable]
private var imageArrayCollection:ArrayCollection = new ArrayCollection();
private function changeSize():void{
this.imageHolder.width = this._imageHolderWidth *(this.widthSlider.value * 0.01);
this.imageHolder.height = this.imageHolder.width;
}
private function addToTileList():void{
var bitmapData : BitmapData = new BitmapData(this.imageHolder.width, this.imageHolder.height );
var m : Matrix = new Matrix();
bitmapData.draw( this.imageHolder, m );
this.imageArrayCollection.addItem({bitmapData: bitmapData, width: this.imageHolder.width, height: this.imageHolder.height});
}
]]>
</mx:Script>
<mx:Image id="imageHolder" source="#Embed('fx.png')" />
<mx:HSlider id="widthSlider" width="400" y="520" maximum="100" value="100" minimum="1" labels="[1%, 50%, 100%]" snapInterval="1" change="{changeSize();}" liveDragging="true" />
<mx:Button label="add to tile" click="{this.addToTileList();}"/>
<mx:TileList x="520" dataProvider="{this.imageArrayCollection}" itemRenderer="TileListRenderer" />
</mx:Application>
second file TileListRenderer.mxml:
<?xml version="1.0" encoding="utf-8"?>
<mx:Canvas xmlns:mx="http://www.adobe.com/2006/mxml" width="100" height="140">
<mx:Script>
<![CDATA[
import mx.utils.ObjectUtil;
override public function set data(value:Object):void
{
super.data = value;
}
]]>
</mx:Script>
<mx:VBox horizontalAlign="center">
<mx:Image id="thumbHolder" source="{new Bitmap(data.bitmapData)}" maxWidth="100" maxHeight="100" />
<mx:Label text="{data.width}x{data.height}" />
</mx:VBox>
</mx:Canvas>
Because it is easier to see it with working source (right mouse button to see the source):
blog.arnomanders.nl/upload/imageResize/imageResize.html