I have a DataGrid, populated with objects in an ArrayCollection. After updating one of the objects' fields, I want the screen to update. The data source is not bindable, because I'm constructing it at runtime (and I don't understand how to make it bindable on the fly yet -- that's another question).
In this situation, if I call InvalidateDisplayList() on the grid nothing seems to happen. But if I call invalidateList(), the updates happen. (And it's very smooth too -- no flicker like I would expect from invalidating a window in WIN32.)
So the question: what is the difference between InvalidateList and InvalidateDisplayList? From the documentation it seems like either one should work.
invalidateList tells the component that the data has changed, and it needs to reload it and re-render it.
invalidateDisplayList tells the component that it needs to redraw itself (but not necessarily reload its data).
invalidateDisplayList() merely sets a flag so that updateDisplayList() can be called later during a screen update. invalidateList() is what you want.
http://livedocs.adobe.com/flex/2/langref/mx/core/UIComponent.html#invalidateDisplayList()
Related
What's the difference between setting ContextMenuPolicy to DefaultContextMenu or CustomContextMenu? From what I can tell, they're the same things? Either way, you get to create a custom context menu if needed.
They are certainly not the same.
While they both could create a custom menu, their behavior is quite different. Consider the QWidget documentation:
The default value of this property is Qt::DefaultContextMenu, which means the contextMenuEvent() handler is called.
This means that you need to specifically override contextMenuEvent() in order to eventually show the context menu. This usually means that subclassing is required and only the widget will handle that event (which could also be ignored) and possibly its menu.
Note that overriding contextMenuEvent() could be done also for special cases of the event management, from the simplest one (accepting it, to avoid propagation to the parent) to more complex situations that need to set up some aspects before letting the default implementation to handle the event as usual.
With Qt::CustomContextMenu, the signal customContextMenuRequested() is emitted.
This means that any object can connect to that signal (and potentially more than once), even a completely unrelated one, and eventually do something from there. This also means that there is absolutely no access to the event, which will always be considered as accepted.
I'm new to Ractive.js and wondering if there's a lifecycle event I can use to know whenever Ractive is done making DOM updates in response to data changes?
My use-case is that I have a grid of boxes (simple divs) rendering some text from the data model. Whenever my data model updates, Ractive is properly updating the DOM for me. But when it's finished with that, I want to dynamically adjust the font size within each box to make sure the text fits.
This is just the first thing that crossed my mind for sizing my text to fit and it might not be the right solution... but I'm surprised I haven't found such a lifecycle event?
Here's the doc I'm looking at: http://docs.ractivejs.org/latest/lifecycle-events. My application is using magic mode to handle updates.
Unless someone more knowledgeable basically corrects the documentation, it looks like there's no lifecycle event to listen to.
However, I've discovered that Ractive's concept of Decorators give me the functionality I was looking for. By passing a Decorator to my Ractive instance, I get passed the DOM nodes created by RactiveJS and I'm able to do whatever work I need to do (in my case, computing whether the text in the node fits in its container and scaling it down in Javascript).
I have an Image being loaded dynamically and being added to my larger application.
After the image is loaded, I then want to grab a bitmap of the display for printing purposes.
The issue is that I can't find any events that are guaranteed to be triggered after the image is rendered on the screen.
FlexEvent.CREATION_COMPLETE sounds closest on paper but doesn't appear to do the trick.
To test, I'm adding a breakpoint to the end of a handler triggered by the event, and seeing whether the image is on screen when the breakpoint is triggered.
I'm being forced to use flex 3.3.
Images are a special case--the component can be complete and visible in the display list before the image data itself is loaded and rendered.
For s:Image, take a look at the Image.ready event.
If you're using mx:Image, look at Image.complete instead. (There's also an s:Image.complete--see the flexdoc comments for how it differs from ready.)
MX Image has a complete event, that I think is what you are looking for. FYI, each Class has a section in its language reference page called "Events." It is frequently instructive to go through these and try ones that look likely. http://help.adobe.com/en_US/FlashPlatform/reference/actionscript/3/mx/controls/Image.html#eventSummary
Have you tried the FlexEvent.SHOW event?
http://help.adobe.com/en_US/FlashPlatform/reference/actionscript/3/mx/core/UIComponent.html#event:show
Edit:
If you can find an event that gets fired after the data is loaded (Event.COMPLETE or FlexEvent.CREATION_COMPLETE or something else), you might be able to get away with doing a callLater() and assuming that the image will be rendered by the next frame. Sort of a hack, but it might be worth a try.
I have a List component using multiple item renderers determined by the itemRendererFunction. When I set the data the first time, it works as expected. Then, when I set the data a second time with new data, it doesn't call the itemRendererFunction and tries to reuse the current renderers even though they don't match the data. Once I scroll, the function is called and the correct renderers are used. I tried calling invalidateDisplayList and such prior to setting the data, but that didn't fix the problem. Any ideas?
It turns out this is a Flex SDK bug. Peter DeHaan provided me with a workaround (re-setting the itemRendererFunction property after the dataProvider is set) and is filing it for a future release of the SDK.
Here's just some ideas:
Try invalidateProperties? Looking at the source I have a hunch it could be that, otherwise, perhaps just start calling every invalidate method you can find till you get the right one.
Another sorta hacky solution might be to take not of current scrolling position (via the scroller on the List) pass in a new array as dataprovider (which will definitely recreate the item renderers) then set the scroll position to the same as it was before the refresh.
Or you could abstract out the selection of the different item renderer into the item renderer itself. :/
FWIW: Here's the link to the Flex bug:
https://bugs.adobe.com/jira/browse/SDK-32018
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.