Changing States does immediate make changes in Flex - actionscript-3

I have an application that switched between different graphs in Flex. Each graph is it's own state. In the MXML I have it set so that the source of the image change when the state changes:
<s:Image id="chartImage"
source.all="{ callImages.all }"
source.classA="{ callImages.classB }"
source.classB="{ callImages.classA }"
/>
I have buttons that successfully change the images. However, I have a small bug which occurs because after the line
this.currentState = chartName;
My code expected the graph image source to be changed, however the actual change to the s:Image element doesn't appear to happen until after the function ends and the screen updates, I assume. So when it grabs chartImage.height, it uses the old one from the state I just left.
Is there a way to have it get the new image (and thus it's dimensions) so I can do calculations with those dimensions on the next line? So far, chartImage.height returns the height from before the state change, but it is different after the function executes.
I could run a timmer after a fraction of a second then execute the lines there, and it would work. However, I'd rather tell it to render the screen and then continue my code. Is this possible? It just seems more elegant.

Is there a way to have it get the new image (and thus it's dimensions)
so I can do calculations with those dimensions on the next line?
Each Flex component must go through it's own validation cycle, which is built on top of the Flash Player's rendering mechanism. There are some great posts out on this, if you perform a Google search for the Flash/Flex Elastic Racetrack.
However, you can force a component to run through it's validation methods in a linear manner by calling the validateNow() method.
It is possible--especially if you have a state transition--that the properties on your Image have not changed yet after you set the currentState variable.

You generally can't change the source of an image in Flex and then immediately check ("on the next line") it's height — the exception might be when the source is a raw bitmap, but even then Flex's layout framework will vary depending on different factors so I wouldn't rely on this.
This is the classic problem with Flex: the beauty (and misery) of the framework is that it progressively renders it's changes to maximize the responsiveness of the app. Google "flex component life cycle" for a ton of resources about the details of this process.
There are a couple of ways to deal with this. Usually you'll want to use binding expressions, since they are designed for exactly this reason: asynchronous layout changes. Don't overuse them but they are a solid tool to keep the codebase simple and flexible.
You can bind to the height of a SparkImage via mxml:
<s:Image id="chartImage" />
<s:Label id="debugLabel" text="{ 'Height of chartImage: ' + chartImage.height }" />
but if you need to run logic I'd recommend using the BindingUtils (in the script block):
import mx.binding.utils.BindingUtils;
protected function someOtherFunctionBlock():void
{
BindingUtils.bindSetter( handleHeigtChange, image, "height" );
}
protected function handleHeigtChange( value:Number ):void
{
// Deal with value change
}

Related

In Flex, how should properties be passed to child components?

I'm new to Adobe Flex, and am working on a desktop Air application. The jist of my problem is figuring out how a child component can be aware of one of its parents properties. The parent might be more than one level up.
Here's a simplified example to illustrate.
I have a custom component that is made up of a few child components, in the example there is only a single button. I have several instances of this custom component next to each other. When one of the child buttons is pressed, I want to generate an event that lets another part of my application know which instance of the custom component the button belonged to. I understand how to create custom events, so I left that part out of the sample code.
My current approach involves creating a property, (e.g. a "position" integer) that I assign to each of the parent components in mxml. The children components also have the position property, which is set to match the parent when the "preinitialize" event occurs. According to the component lifecyle, the preinitialize event occurs in parent components first, then goes down the line of children. Is this safe? Or is there a better way to do this?
Using data binding seems a waste of resources, because the position property never changes after the application loads.
Here are some relevant code snippets.
main.mxml
<s:VGroup>
<components:CustomComponent position="0"/>
<components:CustomComponent position="1"/>
<components:CustomComponent position="2"/>
</s:VGroup>
CustomComponent.mxml
<fx:Script>
<![CDATA[
[Bindable]
public var position:int;
]]>
</fx:Script>
<components:CustomButton
preinitialize="(event.target as CustomButton).setPosition(position)"/>
CustomButton.mxml
<s:Button>
<fx:Script>
<![CDATA[
public var position:int;
public function setPosition(position:int):void
{
this.position = position;
}
]]>
</fx:Script>
</s:Button>
"how a child component can be aware of one of its parents properties."
-> this.parent.propertyName;
The parent might be more than one level up.
-> Then it is not a parent, but an ancestor. You might need to go up the parent chain. this.parent.parent.
Also look into this.document and this.owner. For list based controls these mean different things.
Finally, Look into event bubbling. Sounds like you want your events to bubble up to your top level container.
Generally, this is where a framework/microarchitecture comes into play. You have to keep in mind, that the Flex/Adobe Air library is first and foremost a component library. That means you don't get anything out of the box to help with things such as communication between different part of the app. Sometimes folks will try to use the Singleton Pattern to manage dependencies, but I can tell you from experience that is a horrible mistake that will cost you in the long run as the code becomes very brittle and fragile with high cyclomatic complexity.
Nowadays, there are many frameworks designed to help you with the problem and others that you have and will face. A list of these frameworks can be found through Google, but Swiz, Mate, Robotlegs and Parsley is a great starting point.
There are other frameworks that you may run across such as Cairngorm and PureMVC. Those are generally termed "first generation" frameworks. Personally, I shy away from those because they feel a little too heavy an intrusive.

Flex/AS3: how to manage re-draw of chart when changing multiple chart properties?

I'm missing something fundamental about charting in Flex. I'm creating a custom chart component that includes an autoscale function, which modifies the chart's x-axis and y-axis limits, and provides a new data series for the chart. The custom chart component looks like:
<s:Group ...>
...
private function autoScale():void {
...
// this is where I compute newXmin, newXmax, newYmin, newYmax, startIndex, endIndex
...
haxis.minimum = newXmin;
haxis.maximum = newXmax;
vaxis.minimum = newYmin;
vaxis.maximum = newYmax;
myChart.series.dataProvider = myData.slice(startIndex, endIndex+1);
}
...
<mx:LineChart id="myChart">
<mx:horizontalAxis>
<charts:MyAxis id="haxis" labelFunction="setXLabels()"/>
</mx:horizontalAxis>
<mx:verticalAxis>
<mx:LinearAxis id="vaxis" labelFunction="setYLabels()"/>
</mx:verticalAxis>
</mx:LineChart>
...
</s:Group>
At any time, the user may zoom in/out (code not shown), which calls the autoScale() function.
My thinking, correct me if I'm wrong, is that the above program re-draws the chart FIVE times (once for each line of code shown in function autoScale(). Is it possible to tell Flex to ignore re-drawing changes to the component until I issue some specific command that says, "OK, now I've set everything I need to -- go ahead and redraw the chart"?
I've been reading about invalidateDisplayList, but haven't been able to figure out if this is the intended application for it, and if so, how to apply it here. I've only ever seen invalidateDisplayList applied to custom components in the set and get functions used to pass data in/out of the custom component (see here, for example). In my example above, the properties I'm discussing are all set inside the custom component (e.g. in the autoScale() function). Not sure if that makes a difference.
Any advice appreciated.
Flex's component lifecycle would prevent chart being redrawn 5 times because the properties are modified 5 times with in the statements as you described, that's the beauty of the lifecycle.
In short, most properties change don't right away translate to drawing, but instead a flag is raised indicating that property has changed, such process is called invalidation. The component would then wait until the next redraw cycle, typical a frame after (Flash is a frame-based animation environment). When redraw happens, the code can then evaluate all situations holistically.
Flex's lifecycle provides granular invalidation. Developer could choose from invalidateProperties(), invalidationSize(), invalidatDisplayList() and invalidateSkinState() (for Spark components). As Flex goes through the lifecycle of "validating" these invalidations, commitProperties(), measure(), updateDisplayList(w, h), getCurrentSkinState() would be called to perform the validation. You may find more information about the component lifecycle here, here, and here.
In your case, you should not have to invalidate on your own, unless the charting component does not properly invalidate certain property, you don't need to call the invalidate or validate methods.

How to updating JLayeredPane while the JFrame is running ? java

Having read many tutorials, articles and questions, I am still have confusions about updating the GUI. Plus there are numerous related questions here on this website and still no luck - even though I think my problem is very simple.
Basically, I have a JFrame that has a JLayeredPane as its root container. And I have some layers of JPanels inside it.
The main issue is with updating a particular JPanel in this JLayeredPane. And for this particular Panel, I have implemented an update method that changes the contents inside it.
updatePanel(int para)
//doesn't remove this panel
//removes some existing labels and replaces it with new ones
Once I create the whole Frame, obviously just calling this method won't show any change displayed the frame.
private void static main (String[] args){
WindowFrame frame = new WindowFrame()//WindowFrame extends JFrame
frame.updatePanel(2);
.....
.....
}
And that's where I am stuck. I want to update the contents as the frame is displayed.
I saw these methods mentioned by people but due to nature of problems, I couldn't fully grasped the concepts. Plus the documentation on these methods isn't really helping - at least to me.
revalidate()
validate()
repaint()
How/when should these methods should be called? Or is this not the right way of what I should be doing, given these methods and the problem I am trying to solve?
Thank you for your time.
Basically you need two methods:
revalidate()
This method does the same as invalidate() but in AWT event dispatching thread (i will just call it Swing thread later on)). It updates container and all of its ancestors (parent containers in which this one is placed) layouting.
Basically if you either move something inside this container or place/remove components inside of it you should call this method (or invalidate in case you are performing it in Swing thread, for example inside any Mouse/Action listener body or just inside).
repaint()
This method forces component, all its sub-components (if it has them) and parent container (basically if this component is NOT opaque) to update what they are "painting".
Usually you don't need this method since all standard Swing components know when to repaint themselves and they do it on their own (that ofcourse depends on components UIs and some other things). This method might be useful in case you have your own specific components with some unique painting-way (for e.g. some custom selection over the components) and in some rare problematic cases with standard components.
Also the way this method acts depends on the components placement (due to some Swing painting optimizations) - if you have some massive repaints rolling you'd better optimize them to repaint only those parts (rects) that you actually need to repaint. For example if you change the component bounds inside any container the best choice is either to repaint its old bounds rect and new bounds rect OR repaint rect that contains both of those bounds, but not the whole container to avoid repainting uninvolved in the action components.
So, basically in your case after some changes with panels you should call revalidate on their container (or invalidate) followed by repaint (in case revalidate leaves some visual artefacts) again for the container.
Guess i didn't miss anything and i hope that now you know the basic meaning of those methods.
revalidate at the end of your update method like so .
updatePanel(int para){
.....
.....
this.revalidate(); //of course this refer to the panel
parent.revalidate(); // parent refer to the window
}

symbols placed on the timeline become undefined if stepping backwards

I am using the frames in the timeline of a .swf as pages in a flash app. The user can advance to the next page by clicking a button that takes her to the next frame. Similarly, it is possible to navigate to the previous frame/page as well.
Most of the content is placed on the stage (i.e. created by dragging an instance of a library symbol to the stage) but properties of those instances, such as .visible might be changed via actionscript. Also, some objects are loaded from external flash files and displayed programmatically with addChild / addChildAt.
The problem is, if I am on Frame N+1 and there is an object displayed on the stage programmatically (i.e. with addChild, not by having it placed on the stage) and navigate to Frame N where there is an object that is placed on the stage (i.e. dragged from the library),
then the instance of that object is undefined/null and throws an error if I try to set its properties (like .visible).
The error does not occur if I am moving to the NEXT frame, only if I am moving to the PREVIOUS one. Therefore I assume that some kind of initialization is not getting called while going one frame back.
I was also thinking that the objects would just not "live" to the next timeframe, that is, their value would be lost and re-initialized because of scope, but if there is no dynamically created object on the stage, I can navigate back and forth just fine.
Is there a way to ensure that the objects created on the stage do not disappear while navigating back to the previous frame?
The first, and more useful, part of the answer is this: timeline keyframes and scripts can give conflicting information about display objects - whether they should exist, where they should be, and so on. For example, when you add an item by playing into its frame, and then delete it with script, and then play into its frame again. When this happens, there's no unambiguously correct thing for Flash to do, so it tends to be unpredictable. I believe what generally happens is that once you fiddle with a given object via script, it's considered to no longer pay attention to the timeline - but your mileage will vary.
Having said that, the reason things are different when you play backwards is the second and more arcane part of the answer. Internally Flash functions differently when seeking forward and backwards on the timeline. Flash internally treats keyframes as changes to be applied in the forward direction, so as you play forward, it applies those changes in sequence. When you move backwards, however, from frame N+X to frame N, it doesn't scan through the intervening X frames reversing those changes - it jumps back to frame 1 and fast-forwards along to frame N. Normally, it amounts to the same thing and you don't need to worry about it, but when you get into the twitchy area where scripts and the timeline have a different idea of what should be on the stage, you're liable to see things behave differently depending on which way you jump (as you are now).
The super-short version is, for things to work predictably, try to ensure that any given object gets added, updated, and removed the same way - either all via script, or all via the timeline. When that seems impossible, fiddle with your content structure - usually, the best solution is to change your object into two nested ones, so that the things you want to do with script occur one level higher or lower than the things you want to do with the timeline.
I'm not sure I got your question right, but as3 does not instantiate elements on the timeline as soon as you gotoAndSomething, but later that frame.
That is, you can't
this.gotoAndPlay(10)
this.elementOnTimelineFrame10.DoSomething()
without errors.
I remember using this chunk of code in the past to work around this problem. It uses the Stage.Invalidate() function to wait for an Event.RENDER before trying to access and children, more info (although vague as hell) is here
private function init():void
{
stage.addEventListener(Event.RENDER, stage_renderHandler);
}
private function stage_renderHandler(evt:Event):void
{
// Run your code here
updateChildren();
}
private function enterFrameHandler(evt:Event):void
{
// triggers the RENDER event
stage.invalidate();
}
This also might me very costly (performance wise). I would strongly advise against dynamically adding/removing objects to an existing timeline, is there any way in which you can place an empty Sprite above the timeline animation and use that for all your dynamic content?
Hope this helps

What is the easiest way to find out when a Property of a built in type changes to a certain value?

I'm having an issue with Movieclips inside my Swf resizing to the wrong dimensions. I'm currently tracing the width of the offending clip every half second, and I can see the value change to an incorrect size at some interval in the logged output. I really want to see what code is changing the width. My plan was to extend Movieclip, override the set width property, and dump a stack trace when the value set is too low. This isn't so simple however. Flash is complaining about undefined reference to UI components that are on the Movieclip fla.
Is there a simple way to find out when/why this value changes? I cannot use a debugger.
edit:
The reason I cannot just extend MovieClip is because I am getting my Movieclip object from Event.currentTarget.content after using a Loader. I cannot point my Test (extends MovieClip) object at this return value because it is illegal to do so.
I'll explain the problem a little more and maybe someone will have another idea. I have an app with lots of different windows. They all open to a size of around 750x570. One of these windows contains a FusionChart. when I load this, according to my trace, the background Swf I am using changes to a dimension of about 2712x1930. This doesn't make sense to me because it looks the same size as before and at those dimensions it wouldn't even come close to fitting on my screen. If I then close the window and open another, the new window is tiny, but says it has the same dimensions as the original windows (750x570).
It is almost as if the window is scaling to the huge 2712x1930 without showing a change in size, and then showing the next window (750x570) as a size relative to what the huge window would look like. If that makes sense...
Maybe using a Proxy?
The Proxy class lets you override the default behavior of ActionScript operations (such as retrieving and modifying properties) on an object.
If you can see the trace you are doing and use a debug version of the flash player, try to override the property you want to check and trace the calling stack stack within the Error object:
public class Test extends Sprite() {
// property to watch
override public function set x(value:Number):void{
super.x=value;
// trace the calling stack work only in the flash debug player
trace((new Error()).getStackTrace());
}
}
what do you mean by "Flash is complaining about undefined reference to UI components that are on the Movieclip fla."?
your idea is absolutely the right solution in general... assuming the property doesn't change from within the runtime (which is rare, unless those properties are calculated) ...
when it comes to width and height, they are the two worst properties in the flash player API ... for reading, they are calculated by the space needed by a DisplayObject in parent coordinate space (if you rotate a DisplayObject, than these properties change). for writing, they actually forward to scaleX and scaleY ...