Event once all the custom item renderers have been created/set - actionscript-3

I'm using a custom item renderer in my datagrid, and need to make a button visible or invisible based on if there has been a negative value on any of the values in the renderer. So I'd like to set a flag to false when the first renderer is set off, turn it to true if there's any negative values, and at the end check for the value of the flag. I know I can dispatch a dataChange event for every time the data is changed in the renderer instances, but I was wondering if there is anyway I can know when all of them are done?
Thanks!

There is no such event.
Like any other Flex component, a renderer will dispatch a CREATION_COMPLETE after it's been created. ItemRenderers are generally recycled (the same object gets assigned new data to render), thus listening for CREATION_COMPLETE is not sufficient, unless you disable the recycling.
For a Spark List component, you can disable recycling by setting useVirtualLayout=false on the layout class. I'm not sure if the Spark DataGrid class support this or not. The MX DataGrid may have some other way to do this.
Disabling the recycling, however, can have performance implications. I think your idea w/the DATA_CHANGE event is the best solution:
determine the initial state of the data (ie: are there any negative values)
in the renderer, use the DATA_CHANGE event (or just override the setter for the renderer's data property) to know when the data has changed
When the data changes, dispatch a custom event class that will bubble. This event has a property that tells you if the value is negative or not.
Since your custom event from the renderers will bubble up to the grid, you can add one listener on the grid to handle changes from all the renderers.

You should have a look into RendererExistenceEvents. You should be able to tell when they are all created based on how many items you have in your list or at least how many should be in view at once.
http://help.adobe.com/en_US/FlashPlatform/reference/actionscript/3/spark/events/RendererExistenceEvent.html

Related

What is the invalidateProperties(), invalidateSize() and invalidateDisplayList() functions did while extending a component in adobe flex/air?

What invalidateProperties(), invalidateSize() and invalidateDisplayList() methods are did when extending a component in adobe flex/air ?.
And why these are necessary?
As per the documentation, these functions signal flex/flash to call another function before updating and rendering the display list. This "other function" seems to be for validation (and possibly altering the values if they're incorrect). So by calling an invalidate function, you force a recalculation. Or, in other words, a redraw. This removes any left over graphical artifacts.
That's my explanation via the documentation. Perhaps someone with more experience can build upon my answer.
All these components are based upon the RENDER event so no matter how many changes they go through (ex: x, y, width, etc ...) they are drawn only once per frame. But to get the RENDER event to trigger for each component a stage.invalidate() must be called and parsed on a per component basis. All the component invalidate methods allow you to force a redrawing of the component by skying the RENDER event step or in other cases by starting the RENDER event workflow.

In AS3, what property(ies) determine whether an InteractiveObject can receive the stage focus via mouse click?

In AS3, stage.focus get/sets the display object with the focus. Focus can be assigned to any InteractiveObject instance and anything inheriting from it, such as TextFields, Sprites, and MovieClips.
Incidentally, I looked to see if any of this was part of the ECMAScript spec (since AS3 and JavaScript have that in common) and learned that in JavaScript managing the focus (retrieving it in particular) is much more difficult; older browsers do not support the document.activeElement property, and even newer ones are restricted to returning input-related elements only. If no such element has the focus, all major browsers return the body element - except IE 9, which returns the html element, Chrome 26 returns false in XHTML documents, but apparently you can use document.querySelector(':focus').
In contrast to JavaScript, I discovered that AS3 is very uniform and consistent in that any InteractiveObject can receive the keyboard focus; however, objects (aside from TextField and SimpleButton instances) do not receive the focus via mouse or keyboard interaction by default.
When I first attached an event listener to the stage and listened for the FocusEvent.FOCUS_IN event, it did not fire when I clicked a MovieClip object that I had created on the stage, which led me to the conclusion that MovieClips/Sprites/InteractiveObjects do not receive the stage focus by default through clicking or tabbing.
Meanwhile, if I set either the tabEnabled or buttonMode properties to true, then the event fires when the object is clicked. Incidentally, the documentation for tabEnabled says that it's automatically true when Sprite.buttonMode is true, so tabEnabled seems to be the property of interest (also, buttonMode enables other features as well such as triggering click events when the enter or space keys are pressed when the object has the focus).
I was just wondering if tabEnabled is the correct way to ensure an interactive object receives the stage focus when clicked. Although the documentation for tabEnabled says it causes the object to be included in the [keyboard] tab ordering, it doesn't mention mouse interaction in particular nor does it mention any generic state like "can receive focus". It seems that any interactive object can be assigned the focus manually by setting stage.focus to that object.
Is it correct that InteractiveObject's "tabEnabled" property is the primary property that controls whether focus can be assigned through interaction via both the keyboard AND mouse?
In JavaScript, the HTML5 spec lays out a more complex series of conditions that must be met for an object to be considered "focusable": "An element is focusable if all of the following conditions are met: 1. The element's tabindex focus flag is set. 2. The element is either being rendered or is a descendant of a canvas element that represents embedded content. 3. The element is not inert. *The element is not disabled."
UPDATE: Upon closer inspection, although AS3 does not have a generic "enabled" property, it seems that "mouseEnabled" functions similarly, because when set to false, "the instance does not receive any mouse events (or other user input events like keyboard events)."
UPDATE to first update: The documentation is wrong by including the phrase "(or other user input events like keyboard events)", because focused objects still receive key down/up events despite mouseEnabled being set to false.
As you presumed, it's the tabEnabled property that need to be set to ensure that a InteractiveObject can gain the focus through user input, but for clarity sake, I'll expand a bit my answer :
Any InteractiveObject can have the focus, no matter it's properties. However, there is a few properties that determine how to get the focus, and where the focus is.
Stage.focus indicates which InteractiveObject has the focus, right now; This method is not read-only, and setting it switch the focus to the given InteractiveObject; It is useful to programmatically alter the way the focus is handled in your application.
InteractiveObject.tabEnabled enable the instance to receive the focus via user actions; meaning clicking, tabbing, and using the arrow keys. Note that this property doesn't allow the instance to recieve user inputs; it only allows the Stage to give the focus to this instance.
InteractiveObject.tabIndex permit to set the tab order through the animation. It applies to tabbing only; using the arrow keys ignore this.
InteractiveObject.mouseEnabled has no relation to focus. It allows the instance to recieve Mouse events.
To better understand how focus works in AS3, one could say that an object doesn't take the focus, it is given the focus. The focus is managed by the Stage, and tabEnabled is an indicator for the Stage to know if it should give the focus to an objet or not.
Addendum : The tabEnabled property is false by default because AS3 estimates that most InteractiveObject doesn't need the focus. After all, a objet can receive clicks without needing the focus.
I have already marked another post as the answer, but I just wanted to add some additional info.
FocusEvent.MOUSE_FOCUS_CHANGE and FocusEvent.KEY_FOCUS_CHANGE precede the FOCUS_IN and FOCUS_OUT events and are cancelable, unlike the FOCUS_IN/OUT events.
More importantly, both the target and related objects are populated (i.e. are non-null) in the MOUSE_FOCUS_CHANGE event, whereas the immediately following FOCUS_OUT event will have a null related object if the clicked object's tabEnabled value was false.
By handling MOUSE_FOCUS_CHANGE and KEY_FOCUS_CHANGE events in the capture phase on the stage, you can override the default behavior of the entire focus changing system, and even prevent the focus from ever becoming null as a result of a mouse click.
For example, the default behavior when clicking on an object (regardless of whether tabEnabled is true or false), is for a MOUSE_FOCUS_CHANGE event to be raised that includes the object that currently has the focus, as well as the clicked object. Then, conditionally:
If the clicked object has tabEnabled = true, then it will be assigned the focus, and the FOCUS_OUT/IN events will have both the target and related objects populated.
If, on the other hand, the clicked object has tabEnabled = false, then the focus is set to null, and the FOCUS_OUT event will have a null related object.
Therefore, if you cancel the default behavior that depends on the value of tabEnabled, you can just opt to always manually assign the focus to the related object in spite of tabEnabled being false, so mouse clicks will still trigger FOCUS_OUT events, but they'll never have a null related object.
Similarly, you can override the default behavior for keyboard-instigated focus changes. My KEYBOARD_FOCUS_CHANGE event handler is based in a class that maintains a pushable/popable stack of custom focus loop Arrays, so that when tab is pressed, it checks whether the currently focused object is in the active loop at the top of the stack (or is a child/grandchild of an object in the active loop), and if so, it assigns focus to the object at the next index position (or previous one if the shift key is down). If the object is not in the loop, it (based on a setting) automatically assigns focus to the first object in the active loop that happens to be at the top of the stack. It can even prevent focus from leaving the loop (focus object must be in the loop or a descendent of an object in the loop). The loop can be altered through public methods and can be assigned predefined sets of controls as dialog windows with different sets of controls are opened and closed. When you push a new Array of controls onto the stack for a dialog window, it backs up the currently focused object and current focus array, then moves focus into the new array. When you pop the stack, it restores the old array and returns focus to the object that had the focus when it was backed up. It all works very well, and is far more precise and controllable than the default mechanism.
The focus manager I've built even has a "nullFocus" property, which allows you designate a particular object as the object that should have the focus when the focus would otherwise become null, ensuring the focus is never actually null and events are always processable.
I know this is an old question, but I've been investigating the focus switching for some time now since a client had a novel request. They wanted the + key on the numpad to act like tab and change focus between text boxes.
How I accomplished it was through some trickery I established in my early programming days.
I wrote a function that generates text boxes (below):
function mkText(xpos,ypos,h,w,l:int,multi,sel,bor:Boolean,borCol:uint):TextField{
var textInput = new TextField();
textInput.x = xpos;
textInput.y = ypos;
textInput.height = h;
textInput.width = w;
textInput.maxChars = l;
textInput.multiline = multi;
textInput.selectable = sel;
textInput.border = bor;
textInput.borderColor = borCol;
addChild(textInput);
return textInput;
}
With this, I can create text fields in a loop with an array, such as this:
for(var i:int=0;i<8;i++)
{
cForm[i] = mkText(cFormXpos,cFormYpos,27,69,2,false,true,true,0x000000);
cForm[i].type = TextFieldType.INPUT;
cForm[i].restrict = "0-9";
cForm[i].defaultTextFormat = txFormat;
cFormYpos += cForm[i].height + 13;
}
Each run of the loop will create a new text field with a dynamically assigned instance name, which you can check if you trace the name of any element of the array, for example, instance1, instance2, etc. Each of those can be referenced by their array position as well and even batch formatted or referred to individually. With that approach, I used an incrementer and the general stage.focus attribute to switch between them.
function keyBind(e:KeyboardEvent)
{
if(e.keyCode == 107)
{
stage.focus = cForm[tabOrder];
if(tabOrder < 8)
{
tabOrder++;
}
else
{
tabOrder = 0;
}
}
}
I realize it's a somewhat crude solution to a more complicated issue, but the assigned indices make it easier to achieve tab-esque handling.
I hope this helps.
Cheers
ps. sorry for any subtle spelling errors. I typed this out quite quickly and had to edit a few times.

Getting a list of the rendered items

I have my own custom component. This component extends from a basic container. I want to be able to access the itemRenderer instances that are being visualized. I know that the component mx:list has an internal getter that provides an array of Arrays containing the itemRenderer instances that render each data provider item. I want the same thing. Any idea how of how to do that?
To be more specific: I am setting the selected property of my dataProvider items to true or false. From the updateDisplayList funcion of my ItemRenderer I check for changes of the property and correct the border color of the selected ones. Unfortunately I have to force the updateDisplayList function. I already did this once on a ItemRenderer from a list. Only with the list it was practical because by making my own list I was able to get the list of items being rendered and therefore visualized (cannot be many). It was no overhead to go trough the rendered Items and updateDisplayList. But in this case I can have 100 items. Imagine checking and changing styles on so many items. Thanks
The Flex architects intentionally made this difficult to do, because they are properly encapsulating the component. In short, to even try to do this is a violation of good OOP principles.
That said, about 90% of the things you are probably trying to do can be done by manipulating the data item, and the remaining 10% can be done by using a ClassFactory for your itemRenderer that sets a custom property on your itemRenderer to a callback where you can look at the data available to the containing context and provide back a value based on that.
If you elaborate a bit more on your end goal, I can give you more specifics.
Edit in light of clarification:
You need to make your data object class dispatch an event when it changes (one way is to make it bindable, or just make the selected property bindable). Then, in your renderer, listen for the change event and take the appropriate action.
A second way to handle this would just be to refresh() the collection, storing the selectedItem first (if you care about that) and resetting it once the refresh has finished.
I believe you can access the itemRenderer instances through getChildAt method. Flex 3's container overrides "getChildAt", "numChildren", given that some children are logical children, while some are decorative children such as background, border and scrollbars.
Keep in mind that itemRenderer may not right away become available upon dataProvider assignment, as they may be created during the next component lifecycle. Check with the underlying container's documentation and find out which event to be listened when the renderers are surely created, so you can reliably access them.

What is the complementary event of 'show' for flex displayobjects

Since flex memory management is poor, objects once instantiated dont die very easily (even when they go out of scope), one would need to check on various properties of components. I am using one such thing to know if the screen (which is a display object) is in current view. For this I am turning on a boolean property (currently visible), and I am setting it true on show event of the display object.
What I need to know is, which event (something opposite of show, e.g left?) could be used when the screen is replaced by another display object?
Something like focusIn and focusOut from dotnet.
Or if there is some property which could directly tell me if the display object is currently in view (hasFocus doesnt seem to be giving me expected results).
Thanks.
You can Use PropertyChageEvent check the documentation and base of the newValue and kind property you can do some action :
http://help.adobe.com/en_US/FlashPlatform/reference/actionscript/3/mx/events/PropertyChangeEvent.html
hope this help
Name of the event is: removedFromStage.

Avoid ItemRenders Caching in a Spark List in Flex 4

I have two Spark Lists with custom Item Renderers. I'm working on an application that enables users to drag these Item Renderers from one List to the other. When one of these IRs is dropped in a new position or in another List, I'm updating the dataproviders: I remove the object from one list's dataprovider and add it to the other's dataprovider. This is working ok.
The problem is that sometimes the IR is cached and it doesn't show the correct information, based on its data.
How can I force the Lists to never cache IRs, so that every time I modify the dataprovider all Item Renders re-create all IRs. Performance won't be an issue since I have few items on each list.
A few things..
1) ItemRenderers should always be cached [and reused]. This is one of the benefits of using a Flex list in the first place. I suspect your itemRenderer is implemented inorrectly as to not change when it's data changes. If you share some code for this it would be helpful. But, basically, your itemRenderer should listen to the dataChange event and when the data changes you should update the component's visual display with new data.
2) In Flex 3, I'd have sworn that dragging an item from one list to another automatically updated the relevant dataProviders. Are you sure you need to write manual code to make those changes? You will, though, need code to update your backend as relevant.
Flextras has some good points, but to answer your specific question, you can set useVirtualLayout to false on Spark Lists. This will ensure there is a renderer for every item in your list and thus avoiding the recycling issues. You should really only do this when you have a relatively short list of items though, otherwise you will have performance issues, which as Flextras noted, is the reason Flex recycles renderers.
I put a reset method in my set data to assure renderer variables are reinitialized
override public function set data(object:Object):void
{
if (object == null)
{
return;
}
reset(); // reset locals to their base. ie. x=0, y=0, counter=0
// set up renderer using data
}