Flex 4 DataGrid with floating toolbox ItemRenderer - actionscript-3

At my project I've a DataGrid component that holds some information and, at the final column I need to put a floating tool box.
The idea is when the user hit on the icon's tool box, it appears above a floating tool box like a menu holding some icons to perform different actions.
So far, I've solved the column's ItemRenderer to show the dispatcher tool box icon but to show the upper floating tool box is something that I still can't solve. I've tried to make a custom component ( it's a Canvas that holds a HBox that contains the action's icons ) to hold the tool box's icons and showing it by a Menu control (mx.control.Menu) like this:
private function createAndShow():void {
var myCustomMenu:CustomContextMenu = new CustomContextMenu();
var myMenu:Menu = Menu.createMenu(this, myCustomMenu, false);
myMenu.show(btnToolBox.x + 10, btnToolBox.y + 10);
}
But this approach shows a weird container at the left and top of the page instead of show it at the given point i.e. (btnToolBox.x + 10, btnToolBox.y + 10).
So, can anybody help my out with this?
I was searching through the Internet looking for some examples but, I can't found anything that can help me to accomplish this situation so, if anyone knows a way to solve this or at least can point me somehow, any suggestions would be gratefully appreciated.

Finally, after a long research I found an answer. I created a Custom Component that uses a PopUpAnchor and solution looks like this
<s:PopUpAnchor id="hDropDown" x="{btnToolBox.x-options1.width+30}" y="{btnToolBox.y-6}" includeInLayout="false"
showEffect="{showEffects}" hideEffect="{hideEffects}">
<s:BorderContainer minHeight="0" id="options1" mouseDownOutside="{hDropDown.displayPopUp=false}"
cornerRadius="2" borderWeight="1" borderColor="gray" backgroundColor="black">
<s:layout>
<s:HorizontalLayout gap="5" paddingLeft="5" paddingRight="5" paddingTop="5" paddingBottom="5" />
</s:layout>
</s:BorderContainer>
</s:PopUpAnchor>

Related

Flex 4.6 SplitViewNavigator - Display / Hide Navigators

I have just started a new project and am looking to use the SplitViewNavigator layout for some of my screens as it lends itself well to what I'll be doing.
However not all of the screens should use this layout (homeview being one of them). So I started by setting the visibility of the side view as false.
<s:SplitViewNavigator includeIn="tablet" width="100%" height="100%">
<s:layout.landscape>
<s:HorizontalLayout />
</s:layout.landscape>
<s:layout.portrait>
<s:VerticalLayout />
</s:layout.portrait>
<s:ViewNavigator width.landscape="35%" height.landscape="100%"
width.portrait="100%" height.portrait="30%"
firstView="views.TestView" visible="false"/>
<s:ViewNavigator width="100%" height="100%" height.portrait="100%"
firstView="views.OnSiteFormHomeView" />
</s:SplitViewNavigator>
I know how to access the SpitViewNavigator and the individual ViewNavigators. So I did the following in my home view (as a test) but nothing seems to happen. (the other navigator stays full screen). I've tried attaching the code to the intialize and creationcomplete events.
// Create a reference to the SplitViewNavigator.
var splitNavigator:SplitViewNavigator = navigator.parentNavigator as SplitViewNavigator;
// Create a reference to the ViewNavigator for the Detail frame.
var sideNavigator:ViewNavigator = splitNavigator.getViewNavigatorAt(0) as ViewNavigator;
var detailNavigator:ViewNavigator = splitNavigator.getViewNavigatorAt(1) as ViewNavigator;
sideNavigator.visible = true;
I assume that I need to somehow make it redraw the screen/navigators. I've tried calling the initialize function on the splitviewnavigator and also the individual navigators but it seems to make no difference.
To answer my own query. I found that it works for me between views (popping/pushing) so I can just do the following (from a single view screen):
sideNavigator.visible = true;
sideNavigator.pushView(SideViewHere);
detailNavigator.pushView(NewMainView);
and the reverse would be:
detailNavigator.popView();
sideNavigator.visible = false;
sideNavigator.popView();
Which gives me everything I need.

process facebook feeds dynamically in adobe flash builder

I am trying to process the user feeds retrieved from facebook by dynamically adding them to the flash app, and i need the feed to be displayed in a box with its publisher name and picture beside it (as normal)..
the question is how could i display them aligned under each other if i don't know their heights? is there a way to just add them under each other without specifying the height?
like in html adding divs under each other?
and other question how to add a scroll bar if the content exceeds the flash window?
iam new to as3 & flash so any advice will help.. thanks..
my code:
protected function getFeedsHandler(result:Object,fail:Object):void
{
if(result)
{
var i:Number;
for(i=0;i<10;i++)
if(result[i])
{
var fdLbl= new Label();
addElementAt(fdLbl,1);
fdLbl.text=result[i].message;
fdLbl.x=20;
fdLbl.y=(i+2)*100;
fdLbl.width=400;
var fdImg= new Image();
addElementAt(fdImg,1);
fdImg.source=FacebookDesktop.getImageUrl(result[i].from.id,"small");
fdImg.x=20;
fdImg.y=(i+2)*80;
fdImg.width=400;
var nameLbl= new Label();
addElementAt(nameLbl,1);
nameLbl.text=result[i].from.name;
nameLbl.x=20;
nameLbl.y=(i+2)*90;
}
}
the interface:
<s:Button id="loginoutBtn" right="10" top="10" label="Log out"
click.loggedin="logout(event)"
label.loggedout="Log in" click.loggedout="login(event)"/>
<s:Form includeIn="loggedin" left="70" top="10">
<s:FormItem label="User">
<s:Label id="nameLbl" text=""/>
</s:FormItem>
<s:FormItem label="birthday">
<s:Label id="brthday"/>
</s:FormItem>
<s:FormItem label="feeds">
<s:Image id="feedImg"/>
<s:Label id="feedLbl" x="0"/>
<s:Label id="statusLbl" width="405"/>
</s:FormItem>
</s:Form>
<s:Image id="userImg" includeIn="loggedin" left="10" top="10" width="50"/>
So it looks like you're using Flex and specifically you're using the spark components. In using Spark there's a couple of options on how you would achieve this, one option is to put the component you made above into a VGroup. The VGroup vertically stacks visual components, it has a property called gap you can set to add or remove spacing between the components (number of pixels between each object nested into the VGroup). The addition of a s:Scroller component wrapping the VGroup will give you the scroll bars, essentially the way this works is you set the size on the s:Scroller to the size you want to visible (can be a percentage like 100% width/height of the view/container), then you set no explicit size on the VGroup, the VGroup will expand to have a height equal to the height of all the components nested in it plus any padding plus the gap space, the scroller will take care of figuring out how big the scroll tab button should be and adjust the scrollRect on the VGroup for you, essentially it's going to work like magic :). This would look something like the following:
<s:Scroller width="100%" height="100%">
<s:VGroup id="loadedContentVGroup">
<yourpackage:YourCustomComponent/>
</s:VGroup>
</s:Scroller>
If you don't constrain the scroller's height and width it will not work as it doesn't have a defined region to draw in and will just become as large as it's children (the nested components). In all likelihood you would add elements to the VGroup in AS3 so you'd probably want to give it an ID.
Your other option is to use a spark List and then set your visual component as the itemRenderer. For each data element in the data provider for the list (some sort of collection class, ArrayCollection, XMLCollection etc.) it will set an element of the array as the "data" property on your visual component. You would then use bindings to the data property in your visual component to make sure if the renderer is re-used/recycled the elements within it update automatically. Here's an example of that:
<s:List dataProvider="{new ArrayCollection([{name:'Shaun', birthday:'04-28-1983', imageSource:'someImage.png'}])}"
itemRenderer="views.YourCustomComponent"
width="100%"/>
In your case the dataProvider for the list could be assigned in the result handler code you have above, it appears result is an array so you can just wrap it in an ArrayCollection like myList.dataProvider = new ArrayCollection(result);
Here's a potential view definition for a single entry in the list (the itemRenderer class used above)
[views.YourCustomComponent]
<?xml version="1.0" encoding="utf-8"?>
<s:VGroup xmlns:fx="http://ns.adobe.com/mxml/2009"
xmlns:s="library://ns.adobe.com/flex/spark"
implements="mx.core.IDataRenderer">
<fx:Script>
<![CDATA[
private var _data:Object;
[Bindable(eventName="dataChanged")]
public function get data():Object
{
return _data;
}
public function set data(value:Object):void
{
if(_data == value)
return;
_data = value;
dispatchEvent(new Event("dataChanged"));
}
]]>
</fx:Script>
<fx:Declarations>
<!-- Place non-visual elements (e.g., services, value objects) here -->
</fx:Declarations>
<s:Label text="{data.name}"/>
<s:Label text="{data.birthday}"/>
<s:Image source="{data.imageSource}"/>
</s:VGroup>
There are certainly caveats and alternatives to these answers but this will hopefully get you going in the right direction, if you're doing this for mobile development be sure to check out the recommendations with regard to creating renderers for mobile, the idea here is to reduce the processing needed for creating and re-using renderers on mobile as much as possible to lighten the load on the CPU and memory.
One other thing to note it appears your mixing defining the view in AS3 and MXML, while this is technically okay I find it to be a bit confusing myself. I would normally define the entire layout in MXML, or if need be entirely in AS3. If defined in MXML and a component needs to be conditionally hidden by code I would just toggle the visible/includeInLayout properties. I suppose this is just a preference but it seems it could get hairy determining what is causing particular layouts to occur when you have to look between the two to piece it together.
References to the AS3 reference for classes used:
http://help.adobe.com/en_US/FlashPlatform/beta/reference/actionscript/3/spark/components/VGroup.html
http://help.adobe.com/en_US/FlashPlatform/beta/reference/actionscript/3/spark/components/Scroller.html
http://help.adobe.com/en_US/FlashPlatform/beta/reference/actionscript/3/spark/components/List.html
Details on custom item renderers http://help.adobe.com/en_US/flex/using/WS03d33b8076db57b9-23c04461124bbeca597-8000.html <-- references Jeffry Houser a regular on SO with the name www.flextras.com

How to set DefaultComplexItemRenderer background alpha to 0

I have a simple list with a tileLayout of images. From the examples I've looked at it looks like i'm supposed to use the DefaultComplexItemRenderer. It works, and my array of images loads fine, but each item has a solid background. I need the background behind each image to have an alpha of 0. How Can I set that?
In the past i've just made a custom itemRenderer, and overrided the drawBackground function on itemRenderers, but DefaultComplexRenderer doesn't have a drawBackground function to override.
Is there another simple solution in the flex code? OR it would be awesome if someone could show me how to make a custom DefaultComplexRenderer.
NOTE:
This is a Flex MOBILE project. I know some itemRenderer's aren't friendly with mobile. Adobe says to "always do item renderers in AS3 rather than mxml" so, keep that in mind.
Thanks!
Here's my code:
<fx:Declarations>
<s:ArrayList id="arrList">
<s:BitmapImage source="assets/images/one.png" scaleMode="letterbox" smooth="true" width="100%" height="100%"/>
<s:BitmapImage source="assets/images/two.png" scaleMode="letterbox" smooth="true" width="100%" height="100%"/>
<s:BitmapImage source="assets/images/three.png" scaleMode="letterbox" smooth="true" width="100%" height="100%"/>
<s:BitmapImage source="assets/images/four.png" scaleMode="letterbox" smooth="true" width="100%" height="100%"/>
</s:ArrayList>
</fx:Declarations>
<s:List id="extrasList_list" width="100%" height="100%"
dataProvider="{arrList}"
itemRenderer="spark.skins.spark.DefaultComplexItemRenderer"
horizontalCenter="0"
verticalCenter="0">
<s:layout>
<s:TileLayout requestedColumnCount="-1"
requestedRowCount="-1"
horizontalGap="10"
verticalGap="10"
orientation="rows"
columnAlign="justifyUsingWidth"
/>
</s:layout>
</s:List>
Things I've tried:
this in my main css file...
s|DefaultComplexItemRenderer {
contentBackgroundAlpha:0;
}
but i get this warning, and it doesn't work...
-Cannot resolve namespace qualified type 'DefaultComplexItemRenderer' in CSS selector 'DefaultComplexItemRenderer'
[Edit]
The contentBackgroundAlpha and contentBackgroundColor styles for a Flex List are somewhat misleading! You generally want to style the item renderers. In the context of a list, these styles only affect a tiny bit of "chrome" that can appear around the list. See below for details on styling the renderers.
If you just want to show an image, the IconItemRenderer is the way to go. It extends LabelItemRenderer so it's optimized for mobile and also has two text fields as well.
Flex List components recycle item renderers to be efficient, and only create as many renderers as needed to display what is currently visible. To do this, the list populates the renderer's data property. So you want to configure your item renderer using this data property.
An efficient way to do that is to override the setter function for data. Create a new Actionscript class that extends IconItemRenderer add this to it:
override public function set data(value:Object):void
{
super.data = value;
// IconItemRenderer already has a BitmapImage component, it's property name is iconDisplay
// your ArrayList should therefore only contain Strings representing the image sources
// note how I've changed your ArrayList in the declarations tag below
iconDisplay.source = data.imageSource;
}
You'll likely want to configure that iconDisplay BitmapImage to look how you want it. The method above may get called frequently, so you can put code that only needs to happen once somewhere else... by overriding a Flex component lifecycle method like createChildren():
override protected function createChildren():void
{
super.createChildren();
iconDisplay.scaleMode="letterbox";
iconDisplay.smooth=true;
}
Now tell the List to use your renderer w/syntax like this:
<s:List itemRenderer="com.yourdomain.or.whatever.MyIconItemRendererClass" />
Styling the renderer:
<s:List alternatingItemColors="[0xFFFFFF, 0xFFFFFF]" selectionColor="#FF0000" />
Another way is to override the mobile item renderer's drawBackground() and/or drawBorder() protected methods and draw your own stuff w/the graphics api (or nothing at all).
Supplying the data:
Instead of giving the list an array of BitmapImage components, you give it an array of objects that contain your data. It's better to use strongly typed objects, but this works too:
<fx:Declarations>
<s:ArrayList id="arrList">
<fx:Object imageSource="assets/images/one.png" />
<fx:Object imageSource="assets/images/two.png" />
<fx:Object imageSource="assets/images/three.png" />
</s:ArrayList>
</fx:Declarations>
I like writing renderers in Actionscript... But there is also an MXML example in the link to IconItemRenderer docs at the top. It also shows how you to set the values of the two text areas in this renderer (with labelField and messageField). You can also specify a function that returns the label/message/icon values (with labelFunction, messageFunction, and iconFunction).
Looks like you should be able to use setStyle('contentBackgroundAlpha', 0); on your DefaultComplexItemRenderer.
Not 100% this is what you're looking for, not really familiar with this class. Any reason you're using this over extending LabelItemRenderer?
edit
I believe you may want to extend IconItemRenderer
Check out this tutorial
http://www.youtube.com/watch?v=EOpsDZaQrOI
Thanks for trying to help guys, but I found the quickest/simple solution to be be just as simple as copying the DefaultComplexItemRender from the SDK into a custom one, and then changing this one line of code
autoDrawBackground="false"
It's simple and it worked.

Best way to show and hide MXML components

I am working on an application where I need to basically have 2 separate screens and I need to be able to switch between them. I am a total noob to Flex & Flash and I have not found anything on how to do this in my 2 days of Googling. It really shouldn't be this hard to do! :)
Here is what I have tried. I created a Flex Project and added 2 MXML Component files called Test1 & Test2 and each simply have a button in them which have a label of Button1 & Button2 so I can see if the correct component is showing. Below is the button code in the Test1 MXML Component file:
<s:Button id="btn1" label="Button1" click="currentState = 'State2'">
In the MXML Application file I have 2 States called State1 & State2. I have added the following to this file as well:
<local:Test1 includeIn="State1" x="0" y="0"></local:Test1>
<local:Test2 includeIn="State2" x="0" y="200"></local:Test2>
I have also added the states to all 3 files:
<s:states>
<s:State name="State1"/>
<s:State name="State2"/>
</s:states>
When I run the application, I see Test1 as I would expect since State1 is the first state listed. When I click the button in Test1 (labeled Button1), I would expect it to now show the Test2 MXML component (since I am changing the currentState to 'State2', but it does not. Test1 is still displayed with Button1 showing.
Can someone shed some light as to what I am doing wrong? Or propose a better (or proper) way of doing this?
Thanks in advance!
Sounds like the states in your Application are not connected to the states in your components. Just giving them the same name doesn't connect them in any way. Anyway, if you're just trying to hide/switch components in your main Application you really only need the states in there.
One option would be to just access the Application's currentState property directly from within the components:
<s:Button id="btn1" label="Button1" click="FlexGlobals.topLevelApplication.currentState = 'State2'"/>
That works, but it's not recommended because it strongly couples the component with the parent Application and in a large project will lead to a mess if you have to refactor (or work with other people).
Another option, is to have each component dispatch an event to let the parent know it should change:
<fx:Metadata>
[Event(name="changeParentState", type="flash.events.Event")]
</fx:Metadata>
<s:Button id="btn1" label="Button1" click="dispatchEvent(new Event('changeParentState'));"/>
Then, the parent would decide which state it should switch to:
<local:Test1 includeIn="State1" changeParentState="currentState='State2'" />
<local:Test2 includeIn="State2" changeParentState="currentState='State1'" />
This way is more generic and just better OOP. However, if you'd want your components to be able to trigger more than just a single state, you might have to do something more complex. This should give you a sense of where to go at least.

A quick way to know the source of scroll bar?

Whenever I use a lot of nesting inside mxml components(including many states) with quite a few Vboxs and Other containers, I always get confused when I see a scrollbar appearing on screen, especially with datagrid inside it(I always want to show scroll bar in datagrid and not on the parent container, for which I usually set the height and width of datagrid smaller than its parent container at run time).
My question is, how could I possibly know (QUICKLY), using debugger, that which component is the source of scroll bar that I see on screen (if there are more than one, then some propoerty of compnent must change when I scroll it up or down).
Thanks.
I realise that this answer isn't using the debugger directly. I mean it as an idea for a simple tool really.
I had a quick go at putting together a simple app that's function is to report what display object is dispatching a mouse wheel event. It does not matter to the app if there is a scrollbar or not, but I guess you could adjust it to your needs. Its a quick start really, here's the code...
<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" layout="vertical" minWidth="955" minHeight="600"
creationComplete="init()">
<mx:HBox id="HBoxWithScrollbar" width="600" height="500">
<mx:HBox width="800" height="800">
</mx:HBox>
</mx:HBox>
<mx:TextArea id="record" height="300" width="600"/>
<mx:Script>
<![CDATA[
private function init():void{
record.text = 'Scroll Record\n';
this.addEventListener(MouseEvent.MOUSE_WHEEL, recordObject);
for each (var obj:DisplayObject in this.getChildren()){
obj.addEventListener(MouseEvent.MOUSE_WHEEL, recordObject);
}
}
protected function recordObject(event:MouseEvent):void{
record.text += (event.target as DisplayObject).toString() + '\n';
}
]]>
</mx:Script>
</mx:Application>
The important thing here really is to see that you can pick up the mouse wheel event at the top level, because it bubbles by default, and isn't cancelable.
http://help.adobe.com/en_US/FlashPlatform/reference/actionscript/3/flash/display/InteractiveObject.html#event:mouseWheel
Once you've got hold of that event, you've got options.
This was built using version 3.6 of the Flex SDK, but it wouldn't take much to build a 4.x version. I am simply displaying "toString()" value of the target display object, but that could be any attribute you want. You'll probably want to put in some error handling for the loop adding events, and also in the event handler. As I said, its just a start, and I hope it helps.