Flex How to delay setStyle until next update? - apache-flex

I have a component composed of two parts, let's say two Hbox A and B in a Vbox.
On a specific call I want to:
- Hide B with B.visible = false
- setStyle("borderSkin", FooBorderOn);
The problem is that the border get drawn before the resizing of the parent Vbox happen,
so i end up with a border Around the Vbox with B invisible :
.....................
. A .
. .
. .
. .
. BLANK SPACE .
.....................
I would like the border to et around the next updated size of the vbox.
Is there something like "do that afer redraw" ? in flex ?
Thanks a lot

Take a look at the callLater method. This will postpone a method call until the next frame update.

It was callLater ... I had it in my memory somewhere

Even if you hide the VBox, HBox B is still there. I would shrink the height of the VBox, set the VerticalScrollPolicy to false (so that the scroll bar won't show), or just plain remove the HBox from the VBox (myVBox.removeChild () ).

There are several ways to postpone actions. If you're developing a UI component yourself, take a look at invalidateProperties / commitProperties. This is a mechanism to not get stuck in update loops: you mark a property to be updated (usually by storing it in a temp var and/or adding a xxxChanged Boolean) and call invalidateProperties(). Flex will then call commitProperties() a bit later - accumulating several changes which might affect each other - where you can do your actual change.
callLater would also be an option, though usually it's not as "later" as one would think :)
(It's the next screen refresh, which could happen quite soon, even before other queued actions)
However in your case, from your description, I think you just missed the "includeInLayout" property. Containers will decide to display (visible) or make room for (includeInLayout) for objects based on those two, separate properties. See also Preventing layout of hidden controls.

Related

ADG drawVerticalLine issue

I have an issue on the AdvancedDataGrid that the verticalLines are not always drawn correctly when the Grid is scrolled
Screenshot:
As you can see it afflicts the entire row up to first groupedColumn.
This happens only when it's upscrolling.
First I thought that it's probably an issue with my itemRenderer
but that is not the case because I found that it's only happing when I set the lockedColumnCount property.
In my case it is set to 10, just to scroll only the groupedColumns.
Without lockedColumnCount there is no such an issue with the lines.
It has nothing to do neither with the footer row, I had the same issue already before I added it.
Anyone has the same problem and found a workaround?
After some painful investigations I found the reason or at least the origin of this behaviour.
It happens only when:
*using grouped columns
*set lockedColumnCount for the ADG
*using a subclass of MXAdvancedDataGridItemRenderer for your itemRenderers
this will produce the bug you can see above when the adg is scrolled up
(it newer happens when it's scrolled down)
it disappears when the grid is redrawn
(after sort or column drag etc.)
and comes back most time (but not every time) when it is rescrolled...
Conclusion:
Don't use the MXAdvancedDataGridItemRenderer when you have groupedColumns and a lockedColumnCount
Create a class which implements:
IDataRenderer, IDropInListItemRenderer, ILayoutManagerClient, IListItemRenderer, IStyleClient
(subclass something like "Group" so you don't have to implement everything,
get inspired from the default renderer AdvancedDataGridItemRenderer for the rest of the implementation)
and use that class for your renderer
and no scrolling drawVerticalLine bug should appear...

Flex DataGrid columns won't resize

I am having serious problems trying to resize columns in a DataGrid. I've been at it for over a day now and am at my wit's end with a headache to boot.
Essentially, I have a TabNavigator component with NavigatorContent children inside. In each one of the NavigatorContent children, I have a DataGrid to which I'm setting the width to 100% (this is needed to be able to handle resizing of the browser window). I am using the excellent filterable DataGrid from Iwo Banas as the DataGrid in each tab.
Now, I am making visible/invisible some columns in each of the DataGrids and this is working fine. However, I find that the column widths are not being set correctly. Whenever I set the column widths (using this code), all of the columns seem to be set to the correct width except for the ones that I have recently made visible and the column immediately to the left of these. The ones recently made visible are very small (though I set their width to 30) and the one to the left of these columns is very large (though I've also set its width to 30).
I think it's something to do with the life cycle of the DataGrids because the first DataGrid behaves fine. It's when I click on the other tabs that I find that the widths of the other DataGrids have not been set correctly.
However, if I "see" one of those problem DataGrids (i.e. it appears on the screen) and the code which resizes the columns runs again, the columns are correctly sized.
I have tried a number of things recommended all over the internet including the questions listed below but to no avail.
This is the code I'm using to resize the columns (taken from this answer)
public static function resizeColumn(col:DataGridColumn, size:int):void
{
var owner:* = col.mx_internal::owner
col.mx_internal::owner = null;
col.width = size;
col.mx_internal::owner = owner;
}
Any and all help would be greatly appreciated.
I have already looked at the following answers.
Flex DataGrid column width: one column to rule them all?
Flex 3 DataGrid Column Width Problem
Flex DataGrid Column Width (<-- this answer got me closest)
Unable to change the column width dynamically in flex datagrid
So, after a huge amount of head wrecking, I finally found a solution (at least to my problem, not sure if it would help anyone else but thought I'd post it here anyway as you never know what could help someone else).
I decided that since calling the resize code when the DataGrid is on screen works then I needed to just do that. So I thought of putting the resize code for the relevant DataGrid depending on the tab clicked. Not that straightforward as there didn't seem to be a straightforward way to implement a click handler for the tabs. I did a quick Google and found this solution.
Essentially, you add a click handler for each tab button by cycling through the children of the tab navigator, getting the button and adding an event listener.
Then, you do what you need to do in the handler.
Code example (slightly different to one from website):
protected function tbGridArea_creationCompleteHandler(event:FlexEvent):void
{
for ( var i:int=0; i < tbGridArea.getChildren().length; i++ )
{
var tab:Object = tbGridArea.getTabAt(i);
tab.addEventListener( FlexEvent.BUTTON_DOWN,myTabClickHandler );
}
}
private function myTabClickHandler(event:Event):void {
switch(event.currentTarget.label) {
// do whatever you need to do here
}
}

Flex TextArea scroll down

I have a TextArea that shows the conversation from selected chat room. For valueCommit event I use: verticalScrollPosition = maxVerticalScrollPosition; And it works fine scrolling text to the bottom. However in one case it doesn't work as expected. There's verylittle text, so TextArea has no scrollbar and then I put a lot of text and a scrollbar is necessary. The text is scrolled almost to the bottom (still a few lines need to be scrolled down). I am pretty sure it gets maxVerticalScrollPosition as if there was no scrollbar. So the question is how can I wait with updating verticalScrollPosition with respect to TextArea's new size (that is now with a scrollbar). I tried calling validateSize and other methods that start with 'validate' but unfortunately with no luck. I also tried the old trick of putting caret at the end of text. So the TextArea's scrollbar makes a difference when getting maxVerticalScrollPosition and I need to update verticalScrollPosition once all measurements are done.
I forgot to mention. I use htmlText.
In the comments of the answer you accepted you mentioned a more elegant solution. Yeah, a timer probably isn't the best option -- you have eventListener cleanup if you remove the component from the stage; if you use the component more than once, you have another timer instance; etc., etc.
If you don't have a lot of post-commit-property actions, the quickest solution would be a call later on the setter of text or htmlText
override public function set text(value:String):void
{
super.text = value;
callLater( scrollToEndAfterTextCommitted );
}
protected function scrollToEndAfterTextCommitted():void
{
this.verticalScrollPosition = this.maxVerticalScrollPosition;
}
I hope that helps.
Best of luck!
Assuming the issue is fixed after you add additional text again, you could probably get by using a Timer, or a call to setTimeout and have the verticalScrollPosition = maxVerticalScrollPosition called a fraction of a second later and see if that fixes it.

Making a Flex DataGrid scroll smoothly

I've noticed that the default behaviour for a DataGrid's vertical scroll bar is to scroll one row at a time. This is all well and good when the rows are all uniform and small (e.g. displaying a single line of text), but gets really ugly as soon as you have rows with variable heights.
I'm curious, is there a way to make DataGrid scrolling "smooth"? For instance, is there a way to have the DataGrid scroll by a set number of pixels, lines of text, etc. rather than scrolling one row at a time?
So far, the only solution I've managed to come up with is to place the DataGrid in a Canvas and have the Canvas do the scrolling instead of the DataGrid. The issue with this approach, though, is that as soon as the Canvas scrolls far enough, the DataGrid headers scroll off-screen. Ideally, I'd like to get the smooth-scrolling nature of the Canvas, but also keep the DataGrid headers visible. Is that possible?
The way that ItemRenderer's work in Flex 3 makes smooth scrolling difficult to achieve. Basically Flex recycles item renderers scrolled off of the top of the list as the display objects used for new data at the bottom of the list. Adobe's implementation of most list components in Flex 3 creates and adds these items as they come on to the screen rather than just off the screen, so they "pop in" and smooth scrolling isn't available. I'm not sure why they couldn't have done it in a similar manner for items +/- one position above or below the current scroll pane, but they didn't, and we're stuck with sticky scrolling by default.
Work-arounds do exist, though the one you've noted (dropping the datagrid into a canvas) negates the display-object saving intention of item renderers and incurs a performance cost. This will be fixed for most list-based Flex components in Flex 4, though it won't be fixed immediately for DataGrid. The DataGrid / AdvancedDataGrid component is maintained by a separate team based in India, last time I heard, and so it tends to be a bit behind the rest of the SDK.
I'd recommend trying something similar to this implementation of a smooth-scrolling list by Alex Harui. I'm not sure exactly how well it'd work for DataGrid or AdvancedDataGrid, but this is the most intuitive technique I can think of for making the list scroll correctly.
Try this... It's still based on Alex's code that was mentioned above. His should still be a great start for removing the snap-to-row behavior. Original source:
http://blogs.adobe.com/aharui/2008/03/smooth_scrolling_list.html
Alex's original some code for smooth vertical scrolling but that was not an issue I had with the DataGrid. It was smooth scrolling horizontally that I needed. I am using the DataGrid in an unorthodox manner for analyzing plain text reports output by our database (great way of providing visual feedback on a document). The code below allows content to go off screen and the user can scroll without that snap-to-column behavior.
You can adapt this to use the same math routines for vertical scrolling and then it will make scrolling possible and ignore the snap to row behavior. In particular switch the usage of the listContent.move method to move the contents vertically and use a inverse of the rounded pixel value you calculate from the vertical scroll bar (as opposed to my using the horizontal).
This method is bit simpler than Alex's method from the link above - a lot less code so try adapting and see how it works.
override protected function scrollHandler(event:Event):void
{
// Override the default scroll behavior to provide smooth horizontal scrolling and not the usual "snap-to-column" behavior
var scrEvt:ScrollEvent = event as ScrollEvent;
if(scrEvt.direction == ScrollEventDirection.HORIZONTAL) {
// Get individual components of a scroll bar for measuring and get a horizontal position to use
var scrDownArrow:DisplayObject = horizontalScrollBar.getChildAt(3);
var sctThumb:DisplayObject = horizontalScrollBar.getChildAt(2);
// I replaced maxHorizontalScrollPosition in Alex's code with "1300" to fix my exact application. In other situations you may finding using some property or different value is more appropriate. Don't rely on my choice.
var hPos:Number = Math.round((sctThumb.y - scrDownArrow.height) / (scrDownArrow.y - sctThumb.height - scrDownArrow.height) * 1300);
// Inverse the position to scroll the content to the left for large reports
listContent.move(hPos * -1, listContent.y);
}
// Go ahead and use the default handler for vertical scrolling
else {
super.scrollHandler(event);
}
}

How do I enable autoresizing for a Flex UIComponent?

I have a class which extends UIComponent and draws directly onto a Sprite contained within. Currently I'm (probably incorrectly) listening to the Event.RESIZE event and drawing the contents when the width and height are non-zero. The problem is that even though I've passed percentage widths to the instance tag, it doesn't appear to be resized along with other Flex components on the page, certainly the resize event isn't being fired at all.
I've hacked it for the moment by binding the width and height to a container which does resize, but how should I really be handling this?
Update :
It turns out I was setting the width and height somewhere in the redraw method (I have no recollection of why I did this!). I shall go hang my head in shame now...
I think you need to provide more information. I'm doing exactly the same, and it works smoothly for me. Perhaps the answer lies somewhere else: e.g. exactly what type of container do you use? Isn't it possible that the space gained/lost on resizing gets allocated to some other component within the cointainer? Try substituting your own component with an mx:Box with some colored background, and see if that resizes with the container.

Resources