Flex and fake Mxml initialisation without actually showing the component, (more insise) - apache-flex

I have a TitleWindow mxml class wich has several components, and listeners.
On its creationComplete and init state i add some listeners which listen for events on its gui.
This TitleWindow is only shown when the user click on a "button", i made TitleWindow a singleton with the following code:
public static function getInstance():MyWindow
{
if ( MyWindow.singleton )
{
return MyWindow.singleton;
}
else{
MyWindow.singleton = new MyWindow();
return MyWindow.singleton;
}
}
I needed a singleton because the user will call this window several times as much as he wants and i only need one.
The problem is the following on some special external events i need to "modify" some listeners (remove listeners and add new ones) on a button from MyWindow, before it was even shown once.
I still have MyWindow.getInstance() in memory when my application starts up.
However adding /removing listeners does not seem to have any effect if he actual rendering of the components did not happen, event when using the following code on app startup.
myWindow= MyWindow.getInstance();
myWindow.initialize();
Not suprisingly if i "show" ('render') the myWindow at least once then the events modifications on the myWindow instance works perfectly.
How can i fake the complete initialisation of this component without showing it on startup ?
Thanks !

Which sort of a container holds your button? If you are using a Multiple View Container you can try setting the creationPolicy to all. Single View Containers create all their children in one go and you shouldn't face this problem.
From Flex 3.0 docs I could retrieve this:
The default creation policy for all containers, except the Application container, is the policy of the parent container. The default policy for the Application container is auto.
This looks like the cause for all your troubles.
Update: I did not mention this earlier, since I thought this was to be expected :) Setting the creationPolicy to all makes your application load more slowly. So, read up on Ordered Creation -- this technique helps you to choose if the controls are displayed all in one go (which is the default behavior, after all of the controls have been created) or step-by-step, as and when they are created.

Related

[Flex mobile]About placing many instances of a custom component

Right now , my development of app is in the optimizing stage. I have a problem when adding one of my components: PlayerInfo, which is extended from Group and has some Labels and Images in it,I have to create 60 of this component and put'm all into a HGroup. But in the process of adding them into the hgroup, my app just stops responding for a few seconds,which is not tolerable. Can I achieve this with less memory usage?
I have read this page and thought if I can do it with any of my components,not only bitmaps.does anyone know how to do that?
here is how I did it:
class PlayerInfo extends Group{
private var name:Label;
private var age:Label;
private var photo:Image;
}
and in my list class:
public function addPlayers(arrPlayer:Array):void{
for(;;){
var player:PlayerInfo=new PlayerInfo();
HGroup.addElement(player);
}
}
Can I achieve this with less memory usage?
Yes! With your current approach; if you have 60 instances of your component, then the app creates 60 instances of the component, renders them all and puts them on the screen; even if they are not currently a view area.
You should make use of a class, such as a List or DataGroup, as #RiaStar suggests. Your custom component, PlayerInfo, should be used as the itemRenderer and the 'list' you are creating these components from should become the List's dataProvider.
Once you do this, then your app will make use of the List's renderer recycling. So, only the visual elements displayed on screen will be displayed to the user. So, if you have 10 items shown on screen from your list of 60; the app will generate 50 less an items. This will make better use of processing power and better use of device memory.
To change your class to a renderer, you will have to implement a dataChange() event handler so that the component updates whenever the list changes the data that the renderer should display.
I don't think we enough information to get a more detailed explanation. What is your dataProvider? What propeties need to be set on your custom component?

Flex4 Right Click Spark List using ContextMenu()

I would like to add custom right clicks to a number of spark list controls.
I have tried the following as an item renderer. (as per the flex 4 cook book).
Full Render code here http://pastebin.com/Kx8tJ1cY
When I right click on the Spark List I simply get the Adobe Default Context menu.
This is the same default behaviour I had before I added any code to this.
Could anyone tell me how to add right clicks to List Items in Flex 4.
Please and Thank you.
I found the problem/solution. You cant use context menus if there are Vboxes or Tab Navigators. Which is insane because it means I cant do relative layout properly or decent variable width design.
Quoted from: http://help.adobe.com/en_US/FlashPlatform/reference/actionscript/3/flash/ui/ContextMenu.html
For example, if a DataGrid control is a child of a TabNavigator or VBox container, the DataGrid control cannot have its own context menu.
Christopher Huyler posted something similar (source code available here). From the article:
Start out by grabbing the Javascript code from Google's code repository.
Step 1 – Setup custom context menu code
Create a new Flex project in Flex Builder. Copy rightclick.js and swfobject.js into the html-template folder of your project. From here, I had to make several changes…
I modified the RightClick.init() function to accept an object and container value as input. This allows me to pass in the name of the application as the object instead of having it be called the same thing every time.
I included rightclick.js and swfobject.js in the header of index.template.html.
I added a new div to the body called “flashcontent”.
I added an onload handler to the body tag to initialize RightClick
I replaced AC_FL_RunContent(…) with new SWFObject(…) making sure to maintain all template variables.
After making these changes, I verified that no right-click context menu appears in my application.
Step 2 – Listen for the rightClick event
Next I added a few lines to the main mxml file of my application to listen for the ExternalInterface event that will be dispatched when I right-click my appliction.
private function handleCreationComplete():void
{
ExternalInterface.addCallback("rightClick", handleRightClick);
}
private function handleRightClick():void
{
Alert.show("Right Click Success!");
}
Step 3 – Dispatch an event to the correct object
Getting the event to the main application is easy, but we actually want the appropriate child object to be notified when the right-click event occurs. Since I am not using any double-click events in my application I decided I would treat every right-click event like a double-click event. Users without a two button mouse (aka Mac users) can simply double-click to get the same menu while users with a two button mouse just have to right-click. Here is how I make sure the event is dispatched to the appropriate object.
private function handleRightClick():void
{
var objects:Array = systemManager.getObjectsUnderPoint(
new Point(mouseX,mouseY));
if (objects.length>0)
{
var object:Object = objects[objects.length-1];
var relatedObject:InteractiveObject;
if (object is InteractiveObject)
relatedObject = object as InteractiveObject;
else if (object.parent && object.parent is InteractiveObject)
relatedObject = object.parent;
var event:MouseEvent = new MouseEvent(
MouseEvent.DOUBLE_CLICK,true,false,mouseX,mouseY,
relatedObject);
object.dispatchEvent(event);
}
}
I hope this helps!

Event control in flex as3 (order of events)

I have a flex application, the display of this application is build with many containers.
I have a FlexEvent.UPDATE_COMPLETE on each of the displayObjects.
What do I want to accomplish?
I want to handle the event only on the top level where it occurred, for instance, if I have a grid and the update occurred in a label somewhere inside, I want to handle the event only on the Grid.
is there a way to accomplish that?
just to emphasize, I don't have any knowledge of the display objects at compile time, only at runtime, the display is being built dynamically to I can't just write the code on the grid, I have to check somehow if the event occurred in a higher level.
I would love some help with this issue, even if it's not code but concept of how to handle this unique issue.
Thanks
Have you considered stopPropagation()/stopImmediatePropagation() on the event, once you handle that event.
Example:
Since your button is in canvas. Your event handler method in canvas would look like this,
function handleEvent(e:FlexEvent):void {
trace("In Canvas's handler");
//do your events...
e.stopPropagation(); //This stops from propagating e to its parent containers, which is an HBOX. The container can be anything at runtime, it doesnt affect the propagation.
}
Try the same example in your other containers too.
Some examples here,
http://livedocs.adobe.com/flex/3/html/help.html?content=events_08.html
http://livedocs.adobe.com/flex/3/langref/flash/events/Event.html#stopPropagation%28%29
Just check for the event.target and ignore if it is not what you're looking for. Or even better: listen for events on top level components and ignore if target and currentTarget doesn't match.
if(event.target != event.currentTarget)
return;
If you can't do this either, check the parents: if parent is your application or the container that holds the top level items, it is a top level item. Based on the structure of your component, it can be anything like
if(event.target.parent == this)
//or
if(event.target.parent == this.theContainer_thatHolds_topLevelItems)
//or
if(event.target.parent is Application)
//or
if(event.target.parent is CustomContainerClassName)

call flex initComplete at a specific time

Below is the overriden on complete function for a preloader in Flex.
private function initComplete(e:Event):void
{
//dispatchEvent(new Event(Event.COMPLETE));
cp.status.text="Configuring... Please Wait";
}
What I want to do is when the app has finsihed loading I want to change the preloaders text to "configuring".
Then I want to go and do a bunch of setup stuff in my code.
Once I've done all the setup I wanted how can I get the Preloader to dispatch its Event.complete from else where in my code?
I tried Application.application.preloader but it comes up null.
So I guess my question really is how to access a preloader from anywhere in my application.
Would a better approach be to have all setup classes as members of my preloader class?
One thing that might help is a Model-View-Controller pattern. Are you using a framework for your application like Mate, Swiz, or Cairngorm?
If you were using Mate, for example, you could do something like this:
Create an AppStateManager class with a property (e.g. applicationState)
Create an EventMap with an EventHandler for the FlexEvent.INITIALIZE event. In this handler, set the AppStateManager.applicationState to something like "CONFIGURING"
Your EventMap has an injector that injects the applicationState property into a view. The injector listens for changes to this property and updates the view. In this case it might just be injected into your main view.
In the main view, you have a public bindable property also called applicationState that gets injected by Mate.
In the setter for this property, you can have an if/then or a switch that does different tasks depending on the state. For example, if applicationState == "COMPLETE", then this.preloader.dispatchEvent(Event.COMPLETE) or something like that.
The details are pseudo-sketched out but the idea is to use Flex's bindings to notify view components when changes have been made, and to have shared objects that maintain state. Not sure if that's what you're looking for...
The component LifeCycle does specific stuff in a specific order, and the near final element is to make the component visible.
It sounds to me like you want to defer this setting of visible to true to do other stuff. But, I imaging if you were making use of the component LifeCycle this would be a non-issue.
What sort of app init stuff do you need to do?

Adding dynamic DisplayObjects in Flex

I am adding DisplayObjects to a Canvas using
ContentContainer.addChild(c);
Where ContentContainer is my Canvas object and c is the DisplayObject I have created at run-time
Some of these DisplayObjects also have children of there own which are added at run-time prior to the DisplayObject being added to the Canvas
I then need to iterate over all the children of ContentContainer but the first time I do this, it says that ContentContainer has no children (ie, ContentContainer.numChildren = 0). If I do it again tho then it is fine and returns the correct number of children.
Is there something I need to call to get ContentContainer to recalculate how many children it has?
As Michael noted it would be helpful to see the code but you might want to look into the Event overview and About the creation policy sections in the docs - http://livedocs.adobe.com/flex/3/html/help.html?content=containers_intro_3.html
Specifically the childAdd event might be what you want to listen for before you iterate over it:
add Dispatched by a component after the component has been added to its container and the parent and the child are in a consistent state. This event is dispatched after the container has dispatched the childAdd event and all changes that need to be made as result of the addition have happened.
=Ryan
ryan#adobe.com
I did a similar task with a callLater in order to wait till after a dragdrop completed before recalculating some tasks. This might work for you.
public function myFunct():void{
//do your adding
callLater(
function():void{
//do your loop
}
)
}

Resources