Flex: Render an unrealized UIComponent to BitmapData? - apache-flex

What is the best way to render to a UIComponent which hasn't been added to the stage? (I'm using UIComponents as renderers for objects, and want to render new copies for image export, filtering, etc.)
Two strategies I've seen/used so far include realizing the component to ensure it calls all the lifecycle methods:
Add the component to Application.application, render with BitmapData.draw(), remove component. This is similar to what I've seen done for printing unrealized components as well.
Add the component to a pop up window, render with BitmapData.draw(), dismiss popup after rendering complete.
I believe both of these just rely on the UI not refreshing while the current thread/event is executing, though (1) could also rely on the component being realized out of view.
Is there a better way?

What I've used in the past with much success is the following:
Create a new instance of your component
Add an event listener for FlexEvent.CREATION_COMPLETE
Set visible=false on the component
Add the component as a child of the main Application
When the component is created, the event listener function will be invoked. The rest of the logic should be put in / invoked from your event listener function
Remove the event listener you added in step #2.
Use ImageSnapshot.captureImage() or captureBitmapData() to capture the visual representation of the component.
Remove the component from the main Application
Process the image data as you need to.
I've used this to snapshot various Flex charting components for use in PDF's generated on the server side. After getting the BitmapData I use the PNGEncoder or JPEGEncoder classes to compress the data, then encode it in Base64 before uploading to the server.

I'm pretty sure you can use the draw() method in BitmapData without having your component on the DisplayList.
For example is use it when I need to modify images I load with the Loader Class. In the init handler I create a BitmapData instance and draw the Bitmap from the loadInfo.content property, then copyPixels() or whatever I need to modify the loaded image

So much of a UIComponent's layout can be tied to it's context. This is especially true for a lot of its derivatives (e.g. HBox) since the fluidity of the layout is tied to it's parent's size and the number of siblings sharing its parents space.
Additionally Flex can be a real pain to get to visually update. Often critical render functions aren't done synchronously ... there are callLater, callLater2 and other hacky approaches that make dealing with the auto-magical layout properties of UIComponents a major headache. Not even calling validateNow or updateDisplayList can guarantee that the layout will be correct on the current frame (instead of a few frames in the future).
I suggest the best thing you can do is not use a UIComponent and try and use a Sprite or other.
Your approach to attach it but make it invisible (alpha = 0, mouseEnabled = false, mouseChildren = false) is decent. You should listen for the FlexEvent.CREATION_COMPLETE callback before you are certain it is properly laid out. Then you can bitmapData.draw it and then remove it from the stage. If you must use UIComponents then I know of no better way.

You can call the lifecycle function manually before using the BitmapData.draw(). Do the following.
createChildren().
commitProperties().
updateDisplayList().
bmd.draw().
The first 2 steps are not 100% necessary, you can put all codes into updateDisplayList(). Because you invoke the function manually, you don't have to worry this is invoked by Flex framework many times.

Related

How to completely initialise a component but not add it to the display? Flex

I need to completely initialize a custom component in my Flex app (i.e. I should be able to access it from action script and get its properties and its children etc), But I do not want to add it to the display or make it visible.
I have tried to add it to my visible component, but keep it visible, but often many of its properties are set only when it is drawn, so i don't get what i need.
Is there a way to add a custom component to some sort of 'Virtual' display, that is not visible to the user?
You could add the component to an invisible Sprite - that way the component itself could both be on the stage and have its own visible property set to true.
Did you try using initialize()? After a view is added to the display list, the initialization stage begins. Calling initialize() before addChild() should let you initialize the view without needing to first add it to the stage.
For more info visit:
http://flexscript.wordpress.com/2008/10/24/flex-component-lifecycle-and-flex-component-framework/
http://blog.deadinkvinyl.com/2008/10/05/flex-3-addchild-and-initialize/
Not sure if possible without adding it to the display list, although I'd wish it were to some extent.
I once had to make custom drag proxy, which didn't work with the real component, because of some weird skinning issues. So instead I had PopupMananger add a box as a popup, added my component to the box, called validateNow on the component, drew it in a bitmap data, removed the popup, and used the bitmap data as the proxy.
So what you were trying was missing a call to validateNow most likely.

Simple AddChild question

I am checking this guy's code...
http://www.codingcolor.com/as3/as3-youtube-chromless-api/
I have download the source code...but I couldn't figure out how he add the play, pause and stop button in the stage. I know in his VideoPlayerControl.as, he has
playbackControl = new PlayPauseButton();
playbackControl.addEventListener(Event.CHANGE,setPlaybackState);
addChild(playbackControl);
in his PlayPauseButton.as. there is not code for the location of the button(x,y)..
I am not sure how he place the control buttons....
Also...Are there anyways to give the button location with object oriented way instead of specify it with static number???
I appreciate any help...
Without reviewing his code...
it sounds like you need to read up on the Flex Component Lifecycle.
In normal cases, the PlayPauseButton will be created and added in createChildren().
the updateDisplayList() method will position and size the elements. Additionally, many components implement a measure() method that will determine the ideal size for it. And many containers have code to automatically lay out the children. If the PlayPauseButton has a measure method and it is added to a container (such as an HBox of VBox) he won't need code to position or size the button as that wrk is already done in the code that he inherits from the Flex framework.

when should I override 1 of the lifecycle methods?

I've read in the flex developer guide that you sometimes need to override one
of the lifecycle methods like: commitProperties and updateDisplayList
but I've written a few flex apps without ever needing to implement them.
when do I need to override them?
First, I 100% recommend studying this presentation by EffectiveUI:
Diving Deep with the Flex Component Lifecycle
and this by Michael Labriola from Digital Primates:
Diving in the Data Binding Waters
They go into things you'll never find in the docs but that are super practical for understanding the Flex Component Lifecycle.
From my experience, the only time you need to worry about overriding core lifecycle methods is if you are creating components. I make a distinction between Application Views and the Components.
Components are things that need to be nearly perfect, highly optimized, and extremely versatile/abstract.
Views are things that you may only need in one Application, but could reuse if you so desired (LoginScreen, ContactForm, etc.).
Views, for the most part, are just adding things to the display list of a more generic component (Canvas, Group, Container, VBox, List, etc.). You, as a View/Application developer, don't really care about how the "dataProvider" creates it's itemRenderers, it just works.
Components are a different story though. When you create a component, you want it to fit perfectly into that system Flex has set up: the Component Lifecycle. It's pretty tough when you first try to build a component like they do, but after you wrap your head around it it's super easy. Here's how I think of the methods when I develop components:
createChildren()
Called once when component is constructed
Called top down. So if Panel calls createChildren, it's createChildren method will call addChild on all of it's children, which calls initialize, which calls createChildren.
If you created a custom component, say a StarRatingComponent, you might want to add 5 stars to the stage when the component is constructed. So you'd override createChildren() to do add stars to the component you're in. By default, though, all Container components in the Flex SDK add their children here (lists do it a bit differently), so you never have to do this if you're building MXML views or something not-to-be-extremeley-reusable.
The next 3 methods are called 1 frame after properties are set.
measure()
If the parent doesn't have any sizing (percent or explicit), it will need to be sized based on it's children's sizes. This can only happen from the bottom up (took me quite a while to really wrap my head around that).
If the parent has explicit or percent sizes, it skips this step.
You override measure if you want to:
Have measuredWidth or measuredHeight return a useful value. So if you build a custom CoverFlowContainer component, and measuredWidth/measuredHeight aren't set (because measure was not overriden), then if you don't specify any sizing on CoverFlowContainer, it would be 0 width 0 height. So instead, override measure and have it set measuredWidth to radius * 2 or something like that, and now you don't need to give it a size!
If the component does not have an explicit or percent size, measure will be used to size the component. Otherwise it's skipped.
commitProperties
Called after measure.
Applies all property changes (from setting properties on the component) to the component (they were stored in private variables for that first frame).
Called a frame after initial property settings.
This is the most important method to override in my opinion. So for your CoverFlowContainer, say you set the hypothetical distance, gap, selectedItem, and tilt properties. When you set them, store them in private variables. Flex will wait a frame, and call commitProperties. In your overridden commitProperties, you can then say layout.updateEverything(selectedItem, distance, gap, tilt); so to speak. So this is the method you override to make all property changes be applied at once.
updateDisplayList
Called after commitProperties
Called top down.
You only override this to set visible properties on the component, such as setActualSize, graphics, etc. But by now (because of `commitProperties), you have all your required variables to update the display set to the right values.
Overall
So from my experience, I worked a lot with these lifecycle methods when creating a component library for things I would use in a million projects:
TitleWindow (my own version)
View3D (for Away3D/Papervision)
Tree and Stack for Flex 4
TextArea (with prompt, expandable, etc.)
ToolTip (easier to skin tooltip)
I needed to make sure everything was updated and rendered perfectly according to the lifecycle. Reading and understanding the Flex 4 Spark Source Code really helps clarify when to override these methods. As does the Openflux Source Code (very simple, clear alternative to the Flex Framework. Not as feature rich so it shows how to bare-bone override those methods to accomplish some pretty advanced things).
When I develop applications and make things like AdvertismentView, MenuView and LoginView, I don't ever think about it because all the components I'm using have already solved those problems (ViewStack, Group, List, etc.). I'm basically just setting properties they've defined and updated in their own commitProperties override.
The only time I would start overriding lifecycle methods in a View would be when I need to access custom variables from outside the view. So say I had a custom RichTextEditor and I created some properties called showFontControls and showStylePanel. When I set those variables, I would probably do what they described in the Data Binding Presentation: accessor sets private variable and calls the invalidation methods, lifecycle methods execute a frame later and I have overridden commitProperties and updateDisplayList to show those panels and fonts. But in practice, that's probably overkill because it wouldn't offer that much of a performance gain for the amount of work it would take. I'd just set up some binding to a visible property in that case. Nevertheless....
The best thing to do to really get into this is to just download the Flex SDK Source and see what they're doing.
Hope that helps.
Lance
Here's another presentation by Deepa (from the Flex framework team) that goes over a lot of the same framework methods, including a nice explanation of why the whole invalidation model exists to begin with:
http://tv.adobe.com/watch/max-2008-develop/creating-new-components-in-flex-3-by-deepa-subramaniam/

Can I make my MXML Component a Singleton?

I have an MXML component in a website that I am reusing in a few different screens.
Based on what the user clicks, the component initializes a few values and starts playing media.
Now if I click through the site, and I play media in screen 1, the component initializes fine and plays the media.
If I then go to screen 2 and play the media, the component initializes twice. Once for screen one, and once for screen 2.
When I then go to screen three, it will start initializing three times.. So it is creating a new instance of the MXML component for each screen!!
How can I make sure that the MXML component only initializes for the screen that I need it to initialize for?
What I really want is that this component always has just one instance throughout the whole application. Is it possible to make that MXML component into a Singleton, so that I always have one instance of that MXML in my application?
Can you explain this a little more indepth? What do you mean by "screens"? It sounds like you have your component nested in some sort of view stack, and that your screens are different sections in the view stack, but it's hard to tell here.
Regardless, I think the solution is to abstract the part of your component that you want to be a singleton from the view. Flex initializes objects in view stacks in a lazy manner by default, but this can be overridden using the creationPolicy property on the ViewStack object. It sounds like your creationPolicy is initializing children as you access them, and something in your component code is causing other instances of the same object to re-fire some initialization code when others are created (possibly in your experimenting for an MXML singleton.)
To truly achieve your desired effect, you should probably just write a bit of actionscript that intelligently re-parents the display object you only want to be created twice. The idea of a "singleton" doesn't make as much sense when we're talking about view objects on screens - to have it displayed in many places, you need many instances, and the process of re-parenting is slightly more complicated than the singleton pattern, so you'll need to do a bit of creative logic around that.
Hope this helps - again, please feel free to post some more source code if you want a more specific response.
Why don't you make the component into a module and use it that way. You Load and/or Unload a module and use it where ever you like! in just calling it as a single item! and you have very much less overheads in your application.

How to tell when an MXML component has totally finished creation?

An MXML component can be quite complex, containing many nested controls, including asynchronously loaded content such as Image/SWFLoader.
Is there one event I can watch for on my component that will only be raised when every control and sub-component has loaded, including SWFs and Images?
CreationComplete will NOT do the trick if you are talking about loading swf content or anything really external like that. CreationComplete gets fired when the MXML components have been laid out as defined in MXML (IE nested components, buttons, boxes, canvasses, etc.), so content that needs to get loaded externally (an image, a swf) does not count.
What you need to do is keep track of everything that you're waiting for and fire off a custom event once all of those elements have loaded.
One possible hackish way to do it would be to listen for whatever load complete event is relevant for each element, then have them call back to the same function that increments a value equal to the number of components you're waiting for. This means you have to pay more attention if you're modifying it, but it also means you don't have to check a boolean for every element that needs to load (IE "if (image1Loaded && image2Loaded && swfLoaded)" etc.)
The onApplicationComplete event?
The creationComplete event should do the trick - creationComplete is called on the parent component after it is called on the children.
You can get some more info on the component lifecycle in the Adobe docs.
In some complex cases, like when your component is considered "finished" only when some data has been retrieved via HTTP or something like that, custom event is your best bet.

Resources