flex how to refresh already created view - apache-flex

How can I refresh view after a certain event?
I have a view which contains multiple groups. I want to show or hide some groups.
onCreationComplete() or initialize() method works only at the beginning of the view creation.

Try invalidateDisplayList() on the view
Let me know if that doesn't do the trick and we'll try some other tricks.

I personally don't like the answer that says to call invalidateDisplayList (sorry no offense Nate nothing personal). I feel it's too vague and doesn't explain what this does under the hood and furthermore you shouldn't have to call it directly in cases such as the one explained in the OPs question. You can simply create booleans that are bindable for each of the groups you'd like to show/hide then in the event handler set those booleans to the appropriate value and if they are bound to the visible and include in layout properties of the containers those containers will internally call invalidateDisplayList after calling set visible and consequently commitProperties.
This is basically what happens under the hood as I understand it: The way this works is values aren't committed or used to update the display until the next frame this way it doesn't get bogged down doing unnecessary layout calculations. So you update the bindable property which fires an event which triggers a notification in the listener (in this case a function that sets the property on your control), that in turn passes along the value to the control which sets an internal flag to update the property and calls invalidateProperties. When it hits the next frame redraw it sees that the properties flag is dirty (true) and then calls commitProperties, this computes/sets the appropriate values (possibly also invalidating then "fixing" the size using invalidateSize() and measure()) and calls invalidateDisplayList, then during the same frame it sees that the display list flag is dirty so it calls updateDisplayList, here it uses the values of the properties to draw appropriately.
You should also be able to achieve this using states, which add or remove children from the display list based on an array of "actions" for each state.

Related

Trigger action on completion of drag action

I'm trying to allow items from a QListWidget to be dragged to a "Trash" (A subclassed widget which accepts drops and does nothing with them).
I know that if I setDropAction(Qt.MoveAction), the items I am removing from the source will be automatically deleted. This works correctly.
My problem is that I also need to trigger an action that updates other widgets who depend upon the contents of the source.
It seems to me that the dropEvent happens before any items are actually removed from the source. I'm having a terrible time trying to figure out this problem. I've thought of two possible solutions:
Find a way to embed the references to the actual QListWidgetItems that are being dragged in the event's QMimeData. This would allow me to do the deletions by hand, before I trigger updates.
Figure out how to wait until the source has been automatically cleared, but I can't find any signals that fire when items are removed from a list automatically.
Aha!
The key I was missing was the mimeData method. This method is called when a drag is started, and in it I am passed a list of all files being dragged.
I first built the meta object to be returned, then I deleted the files being dragged from the list, and called the refresh action that I needed.
Here's an example:
def mimeData(self, items):
m = QMimeData()
m.setUrls([QUrl(i.url) for i in items])
# Clean up the list:
[self.files.takeItem(self.files.indexFromItem(i).row()) for i in items]
self._update_meta()
return m

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)

Flex - Why is my custom event not being registered with the following event listener?

printableInvoice.addEventListener(batchGenerated, printableInvoice_batchGeneratedHandler);
Results in this error:
1120: Access of undefined property batchGenerated. I have tried it as FlexEvent.batchGenerated and FlashEvent.batchGenerated.
The MetaData and function that dispatches the even in the component printableInvoice is all right. It I instantiate printableInvoice as an mxml component instead of via action-script it well let put a tag into the mxml line: batchGenerated="someFunction()"
Thanks.
batchGenerated should be a string.
It looks like your application dispatches an event whenever the batch is generated.
I'm assuming inside your code you have something along the lines of either:
dispatchEvent( new BatchEvent("batchGenerated") );
or
dispatchEvent( new BatchEvent(BatchEvent.BATCH_GENERATED) );
The second way is usually preferred as using variables instead of magic strings gives you an extra level of compile time checking.
The first required parameter of events is typically the type of the event - Event.CHANGE (aka "change"), FlexEvent.VALUE_COMMIT (aka "valueCommit") etc.
This is what the event listener is actually comparing against.
So in your event listener code above, you would want to change the line to be either:
printableInvoice.addEventListener("batchGenerated", printableInvoice_batchGeneratedHandler);
or hopefully
printableInvoice.addEventListener(BatchEvent.BATCH_GENERATED, printableInvoice_batchGeneratedHandler);
If you want to go further, the Flex documentation goes into some detail as to how the event system works, and how the events are effectively targeted and handled through the use of the Capture, Target, and Bubble phases.

Detect when ALL HTML page rendering has taken place

I am working with a pretty complicated .aspx page that is full of controls (Telerik, Ajax, etc.) that all expand, collapse, show, hide, etc. when the page is loaded. Since this rendering happens on the client-side and can take different lengths of time based on the users machine specs, is there a way to detect when all (or some) rendering has taken place (jQuery?) so I can then act on specific elements, knowing they are fully rendered?
JavaScript is single threaded. The time passed to setTimeout is a minimum, but not a maximum, so if you pass something like 10(ms), you essentially are saying "execute this code after all the currently running code is finished."
So, if all the controls use $(document).ready() to do their thing, all you need is:
$(document).ready(function() {
setTimeout(function() {
doStuff();
},10);
});
doStuff will be called after all the functions passed to $(document).ready have run. However, this isn't foolproof. If the controls have their own way of detecting whether the document has loaded, or do their own setTimeout(), you're in trouble. The problem is that JavaScript does not guarantee the execution order of setTimeouts. Sometimes your code may run last, other times it may run before the setTimeouts used for the animation.
One last idea: if all the animation is done using jQuery, then the effects run in a single queue. In doStuff you could add an animation of some sort with a callback and be reasonably certain that the callback would run last.
Whenever I had to wait for multiple things to be ready before proceeding, I would create an array with true/false values. Every mandatory part of the page got an event which, when it is called, updates the specific entry in the array to true. Also, it called a general function which returned true if all values in an array was true, otherwise false.
If that function finally returned true, I would proceed with the execution. It is especially useful if you have to wait for an AJAX call to end but don't want to use async = true. It also is useful if you want to start loading multiple things at once instead of one after another, since they all report ready-state to the same array.
It does however use global variables so you might need to do some optimizations. You might not want to do this approach either if you have a grudge against global variables.
You should place your code inside the jQuery $(document).ready() function. This will ensure that all elements are loaded before the code runs.
http://docs.jquery.com/Tutorials:Introducing_$(document).ready()
I think the doc you need is:
http://docs.jquery.com/Events/load
"I can then act on specific elements, knowing they are fully rendered?"
You can use the load method (linked above) to attach to any element. So if you had a div with an id of "lastElement", you could write
$('div#lastElement).load(runThisFunction);

stack overflow on XMLListCollection collectionEvent

I'm working on a Flex 3 project, and I'm using a pair of XMLListCollection(s) to manage a combobox and a data grid.
The combobox piece is working perfectly. The XMLListCollection for this is static. The user picks an item, and, on "change", it fires off an addItem() to the second collection. The second collection's datagrid then displays the updated list, and all is well.
The datagrid, however, is editable. A further complication is that I have another event handler bound to the second XMLLIstCollection's "change" event, and in that handler, I do make additional changes to the second list. This essentially causes an infinite loop (a stack overflow :D ), of the second lists "change" handler.
I'm not really sure how to handle this. Searching has brought up an idea or two regarding AutoUpdate functionality, but I wasn't able to get much out of them. In particular, the behavior persists, executing the 'updates' as soon as I re-enable, so I imagine I may be doing it wrong. I want the update to run, in general, just not DURING that code block.
Thanks for your help!
Trying to bind the behaviour to a custom event rather than the CHANGE event.
I.e. do what you are doing now, but dispatch and handle a custom event to do the work.
Have you considered using callLater?
Does direct manipulation of XMLListCollection's source XMLList have the same results?
Have you considered something like:
private function changeHandler( event:Event ):void
{
event.target.removeEventListener( event.type, changeHandler );
// your code here.
event.target.addEventListener( event.type, changeHandler );
}

Resources