FLEX: how can I get the width of my linkButton object? - apache-flex

How can I get the width of my LinkButton object ?
myLinkButton = new LinkButton();
myLinkButton.label = "blabla";
myLinkButton.setStyle("fontSize", 24);
myContainer.addChild(myLinkButton);
trace (myContainer.width); //this doesn't work because I haven't directly set the attribute
thanks

First, what does that trace() show? Is it null or undefined or NaN or simply a wrong value?
Then, there are several ways I can think of how you could get around this problem:
Try using getBounds() or getRect(). These methods return a Rectangle object working as the DisplayObject's bounding box (including all coordinates and dimensions). Sometimes Flex behaves a bit weird and returns wrong/off results for the coordinates or dimensions of objects.
Try experimenting with validateSize() and/or measuredWidth. Perhaps you're trying to access the width property too soon so that Flex cannot do the measuring/layouting in time.
Similar idea: what happens if you use myContainer.callLater(trace, [myContainer.width]); (assuming your myContainer inherits from UIComponent)? If you do get a valid result using callLater() but not when accessing width directly then Flex just hasn't had a chance to layout and update the container.
You could also try using this method, which creates a Bitmap from the object and returns the Bitmap's height/width. This is especially useful if you have components with visible = false in your container, because Flex doesn't handle invisible components well in that regard.
Finally, you could try accessing $width in the mx_internal namespace and check that property's value. However, using mx_internal is sort of a very ugly hack because these properties and methods weren't meant for external use and are subject to change any time (so your component could stop working when a new version is released) - so use with caution.

Related

Assigning anchors dynamically in QML

I am creating 2 elements dynamically in QML and need to assign them each an anchor binding. When I add the anchors.right and anchors.left syntax to the properties object of the createObject() function, the anchors are not working:
current_column_on_left = column_component.createObject(parent_element, {anchors.right: previous_column_on_left.left})
current_column_on_right = column_component.createObject(parent_element, {anchors.left: previous_column_on_left.right})
Qt Creator gives me the annotation/error "Expected token ','". I also tried making them strings and camel case, neither of which worked. However, when I add the property bindings separately using Qt.binding() function, everything works fine:
current_column_on_left.anchors.right = Qt.binding(function(){return previous_column_on_left.left})
current_column_on_right.anchors.left = Qt.binding(function(){return previous_column_on_right.right})
Why is the first code block not working? I would prefer not to have the two extra lines of code if I can avoid it.
The error is because javascript doesn't know what property groups are - only qml does.
This is also invalid logic. In createObject(parent_element, {anchors.left: previous_column_on_left.right}) property previous_column_on_left.right is resolved when qreating the javascript {}-style object, which leaves you bound to a fixed anchor which is never changed. But Qt.binding has a function, and resolves nothing when creating the object, which provides you with the correct binding.

Flex: select tree node right after the dataProvider is been assigned / updated / replace

i have a Flex tree control and im trying to select a tree node 3 levels down right after the dataProvider is assigned with a collection object like the following.
basically treeItem1, treeItem2, treeItem3 are the nodes in the tree and treeitem3 is a child of treeItem2 which is a child of treeItem1. Assume these treeItem(1,2,3) are referenced correctly from the collection items.
my problem is that if i wait for the whole component to load completely then select the nodes, it open/select/scrolltoIndex correctly. However, if i were to select the node right after the dataProvider is assigned, then it doesn't even open or select (basically the this.treeService.selectedItem is always null).
can anyone point out what i did wrong? is there anything needs to happen after the dataProvider is assigned?
thanks
this.treeService.dataProvider = oPricingHelper.getCurrentPricingSercicesTreeSource();
this.treeService.expandItem(treeItem1, true);
this.treeService.expandItem(treeItem2, true);
this.treeService.selectedItem = treeItem3;
this.treeService.scrollToIndex(this.treeService.selectedIndex);
I have used the updateComplete event to know when a component (such as a DataGroup or List) has completed rendering after performing a simple task (such as updating the dataProvider reference). Of course, you have to be careful and remove listening to updateComplete because it can run a lot, unless you have a need for it to run.
Something like:
//...some function...
this.treeService.addEventListener(FlexEvent.UPDATE_COMPLETE, onTreeUpdateComplete);
this.treeService.dataProvider = oPricingHelper.getCurrentPricingSercicesTreeSource();
//...rest of some function...
private function onTreeUpdateComplete(event:FlexEvent):void {
this.treeService.removeEventListener(FlexEvent.UPDATE_COMPLETE, onTreeUpdateComplete);
this.treeService.expandItem(treeItem1, true);
this.treeService.expandItem(treeItem2, true);
this.treeService.selectedItem = treeItem3;
this.treeService.scrollToIndex(this.treeService.selectedIndex);
}
I'm not positive your experiencing the same issue but I seem to have the same type of problem with using the advanced data grid, it appears in these cases where the dataprovider is acceptable as multiple types, the components do some extra work in the background to wrap things up into something Hierarchical (HierarchicalData or HierarchicalCollectionView) and in doing so the dataprovider setter call is not synchronous (so it will return before actually having assigned the internal property storing the dataprovider). I've used callLater in this case with moderate success, callLater is generally a bad practice but basically adds a function to a list of functions to call once background processing is done, so this is assuming that something in the dataprovider setter called UIComponent.suspendBackgroundProcessing() and that it will subsequently call UIComponent.resumeBackgroundProcessing() and then it will execute the list of functions added by using callLater. Alternatively you could use setTimeout(someFunction,1000).
These are both "hacks" the real solution is to dig into the framework code and see what it's really doing when you tell it to set the dataprovider. Wherever you see that it actually has set the dataprovider you could extend that class and dispatch an event that you could listen for to run the function to do the selections after this point.
If anyone has a better solution please by all means correct me (I would love to have a better answer than this)

Smooth sliding animation in Flex with large amounts of components

I have a component I created that works like a Viewstack but the next index component slides in from one of the four sides. I've got it working well enough that it's acceptable to use, but I want to make it more efficient.
Right now I'm using a Canvas as the base component, I create a snapshot of the current view using an ImageSnapshot (new Bitmap( ImageSnapshot.captureBitmapData( this ) )), and I slide the new index on top of that image on index change.
I'm basically looking for suggestions on how to do this a better way. By taking the Image after the component loads, and after the slide happens, I've gotten the initial jaded moves down to a minimum, but we normally use this for transitioning grids so it's almost always slow on the first or first couple slides.
Here's what some of it looks like so far:
private function creationComplete(e:Event):void
{
tmpImage.source = new Bitmap( ImageSnapshot.captureBitmapData( this ) );
}
public function set selectedIndex(value:int):void
{
if(_selectedIndex == value + 1)
return;
_selectedIndex = value+1;
var obj:UIComponent;
tmpImage.height = height;
tmpImage.width = width;
tmpImage.visible = true;
tmpImage.x = 0;
//tmpImage.includeInLayout = true;
for (var i:int = 1; i < numChildren; i++)
{
obj = UIComponent(getChildAt(i));
//obj.x = width;
if(i == _selectedIndex){
obj.visible = true;
objDisplay = obj;
}
else
obj.visible = false;
}
mv1.target = tmpImage;
mv2.target = objDisplay;
switch ( direction )
{
// X/Y sliding logic
}
parEfect.play();
tmpImage.source = new Bitmap( ImageSnapshot.captureBitmapData( this ) );
}
If you're wondering, I'm using index 0 of the canvas for the image, and offset my custom selectedIndex by 1.
I'll post more of it if need be, but I want to keep the question down to a minimum and this pretty much sums it up.
Any help is greatly appreciated! I really want to get this component to perform better. Also, this has to be done using Flex 3
What are mv1 and mv2? Are they Flex Effects? If so they are notoriously slow, I recommend using TweenLite. If you absolutely need to use them set suspendBackgroundProcessing = true on them. Last but not least, make sure you do not have a layout set on them. If you do you are causing a re-layout every frame which can easily bog down animation.
You are probably getting some memory hits from all the components being created and then immediately being converted to an image. I would definitely try adding some intelligence at creation time. Try checking the memory usage and test against maximum mem load before creating the image:
http://livedocs.adobe.com/flash/9.0/ActionScriptLangRefV3/flash/system/System.html
However, I would need to look at what is being created in the object. I suspect that you are loading some pretty heavy objects in each of the views. And if you are loading data from the server for each object, there will be a lag, possibly.
Set up a priority queue for creating objects within the class that is being created . . . e.g., if you have a menu system that is hidden by default, load the front-end, then load the menu drop-down only when a user clicks on it, or after all other immediately visible objects have been created. You will also have the advantage of being able to take a snapshot when all the immediately visible objects are in place, and before the hidden objects are created.
Finally, add event listeners after object creation, if you can, and remember to remove listeners asap.
Do you use Flex 3 or Flex 4?
Because if you use Flex 4, I would recommand to use Animate Filter with Shader Filter.
Shader Filters use Pixel Bender so you can build a shader in Pixel Bender that will do the transition between your 2 images.
See these 2 videos for more info :
http://tv.adobe.com/watch/codedependent/pixel-bender-shaders-and-flex-4/
http://tv.adobe.com/watch/codedependent/shader-transitions-in-flex-4
It would be helpful to see how you're creating your Move effects, mv1 and mv2. It is possible to set combinations of the *From, *To, and/or *By attributes--or various manipulations of the properties that control the tween's speed/duration--that together can cause "jitter" or "jerkiness" in the resulting animation.
of course, it's also possible that you're hitting against a performance barrier of some sort, but I suspect it's something more insidious. Simple translation ("x/y sliding") of any clip should perform relatively well, as long as the clip hasn't been rotated, skewed, or scaled; and as long as the processor isn't completely maxed out with some other operation that's going on at the same time.
In most cases, when defining a Move effect, you want to set as little information as possible, and let Flex compute the optimum values for the other things. Usually, this means setting only xTo and yTo.
Also, be sure to call end() on your tweens before you start setting up the new values (just in case any previous sequence is still running).
Finally - make sure that you're not competing with the component's layout manager during the tween. While the tween is running, you should disable the layout completely (by setting autoLayout=false on your container component)--or you can change the layout (temporarily) to an absolute layout. Either way, the tween must be allowed to move things around while it's running, and the moving of stuff must not cause the layout manager to recompute things until after it's all over. Once it's finished, you can re-enable whatever layout manager you had originally.

Flash/Flex: "Warning: filter will not render" problem

In my flex application, I have a custom TitleWindow that pops up in modal fashion. When I resize the browser window, I get this warning:
Warning: Filter will not render. The DisplayObject’s filtered dimensions (1286, 107374879) are too large to be drawn.
Clearly, I have nothing set with a height of 107374879.
After that, any time I mouse over anything in the Flash Player (v. 10), the CPU churns at 100%. When I close the TitleWindow, the problem subsides. Sadly, the warning doesn't seem to indicate which DisplayObject object is too large to draw. I've tried attaching explicit height/widths to the TitleWindow and the components within, but still no luck.
[Edit]
The plot thickens:
I found that the problem only occures when I set the PopUpManager's createPopUp modal parameter to "true." I don't see the behavior when modal is set to "false." It's failing while applying the graying filter to other components that comes from being modal. Any ideas how I can track down the one object that has not been initialized but is being filter during the modal phase?
Thanks for reading.
This might not be the case in your application, but I have come across similar cases where a height or width of an object has been set to some unreasonable big number as the result of misuse of an unsigned integer in calculations for positioning, height or width.
Schematic code for such a scenario could be like this:
var offset:uint = 30;
var position:uint = txt.textHeight - offset;
divider.y = position;
The code wrongfully assumes that txt.textHeight will always be bigger than 30. If it is not, txt.textHeight - offset will be a negative number, that when stored in an uint will instead become a very large number.
Let's say for example that the text in txt, presumed to be a long multiline text, instead is a single line that is 20 pixels heigh. The result will then be -10, and when stored in the uint var position, the value of position will be 4294967286.
The above is crappy code, an example, but in a real world situation the uint problem can occur in some more complex way, that might be harder to spot right away. I guess it is seldom a good idea to use an unsigned integer for stuff like x and y positions, that can have negative values.
You could write some code to recursively step down the hierarchy of DisplayObjectContainer and DisplayObject objects and check for the large height.
Should be pretty simple to write. A function something like this should do the trick:
function RecurseDisplayObjects(DisplayObject obj):void
{
//check for height and do a trace() or whatever here
if(obj is DisplayObjectContainer)
{
var container:DisplayObjectContainer = obj as DisplayObjectContainer;
for(var i:int=0; i<container.numChildren; i++)
{
RecurseDisplayObjects(container.getChildAt(i);
}
}
}
You would need to start this off by passing it the top level DisplayObject in your application. (possibly obtained with DisplayObject.root)
The other option you have is to get the Flex framework source and modify it to give you a more meaningful error.
The problem is probably not in your TitleWindow, but in objects below it. The filter failing to render is probably the blur filter flash applies over everything below the modal dialog. If one of the objects on the stage is too big to apply blur on it in real time, you get the error you mentioned.
I solved that problem by applying a mask to the object below the titlewindow, set to the size of the stage. That will probably solve your problem but you should definitely look into why something gets to that size, doesn't sound healthy. :-)
Sadly I have no idea, but we're trying to track down a similar issue in ours. Maybe this will help?
http://www.mail-archive.com/flashcoders#chattyfig.figleaf.com/msg48091.html
I had a similar issue, tracked it down to an alpha filter applied to an object scaled to -0.23453422334. Once I rounded the scale to 2 significant digits everything worked fine. A difficult error to track down however.

'Pre-measuring' Flex Components

I'm implementing a custom Flex component that provides a scrollable viewpoint onto a (possibly very large) data grid. I'm using the ItemRenderer pattern, such that I only have UIComponents for the elements visible on the screen at a given time. In other words, something similar to the standard DataGrid control.
One requirement I have is to dynamically size the grid cells to fit the provided data, such that the column widths and row heights are known up front. (The column widths and row heights can't fluctuate as the user scrolls and new cells come into view.)
This requirement implies a 'pre-measure' phase of the entire grid to be performed when the component's dataSource or itemRenderer is changed. I'd like to use the standard Flex component measuring operations to perform this pre-measurement phase.
My current strategy for this pre-measure phase is to:
Obtain an itemRenderer instance
Initialize the itemRenderer
For each cell in the data source:
Set the itemRenderer's 'data' object to that cell's data
'commitProperties()' on the component
'measure()' the component
Update column width/row height appropriately based on measurement results
I'd rather not attach the itemRenderer to the application's display list, but that means it won't be initialized by the framework. Also, I need the renderer's initialization and commitProperties/measurement phases to occur synchronously. I'm scared of how much of the Flex component lifecycle management framework I'll have to replicate to accomplish this.
So I call on those more experienced than I for words of wisdom:
Any thoughts on the feasibility of this strategy?
Any suggestions on how I could elegantly make use of the framework to perform this measurement for me?
Any better strategies to determine cell size?
I studied the framework code a bit, and if initial results are an indication, this isn't as painful as I feared. The guts of it:
var renderer:IListItemRenderer = getRenderer();
renderer.initialize();
for each (var cell:Object in cells) {
renderer.data = cell;
renderer.validateProperties();
renderer.validateSize(true);
// Access renderer's size properties here
}
Passing the 'recursive = true' flag to validateSize is the key that I was missing previously. Unfortunately there's no equivalent flag for validateProperties, so I'll probably have to implement that myself to make it reliable for arbitrary ItemRenderers.
I've never applied itemRenderers this way, so, not sure how much this would come into play with you're approach, but are you setting
super.data = data
at the top of your renderer's data setter? i.e:
override public function set data(value:Object):void
{
super.data = value;
...
}
If not, you might try adding that and see if it removes the need for a recursive flag in validateProperties().

Resources