Flex conditional data binding - apache-flex

I have got two labels in my flex mxml component.
first one shows playheadtime of videodisplay and another is also used for same purpose. the difference is that when we are in add mode(decided from a flag variable) both should show current playheadtime using binding. but when we are in edit mode(again decided from flag) the latter label should remain static, to be more specific, the value retrived from database.
how can I do that using actionscript. I tried ChangeWathcer but I found it a bit tricky. Is there any other simpler way or am I missing something.
following is my code.
private function init():void
{
if (queFlag == 'a')
{
// timeLbl.text = currentTimeLbl.text using some binding mechanism
}
else if(queFlag == 'e')
{
// timeLbl.text = 'value retrived from database' ;
}
}
here currentTimeLbl shows videoDisplay playheadtime so it changes dynamically as video plays.
please help me out.

You could do it in something like the following:
<Label id="timeLbl" text="{timeLabelText}"/>
<Label id="currentTimeLbl" change="dispatchEvent('currentTimeLblChanged')"/>
[Bindable(event = "queFlagChanged")]
[Bindable(event = "currentTimeLblChanged")]
private function get timeLabelText():String
{
if(_queFlag == 'a')
{
return currentTimeLbl.text;
}
else
{
return 'value retrived from database';
}
}
public function set queFlag(value:String):void
{
_queFlag = value;
dispatchEvent(new Event("queFlagChanged"));
}

Here is a very short way of conditional binding in Flex. If you code the conditions into MXML curly-bracket-bindings they will be transformed by the MXML compiler to listeners on all objects participating in this expression.
Here is a working example:
<mx:CheckBox id="flagBox"/>
<mx:ComboBox dataProvider="{['a','e']}" id="flagBox2"/>
<mx:TextInput id="txtBox"/>
<mx:Label text="default: {txtBox.text}"/>
<mx:Label text="conditional (bool): { (flagBox.selected)? txtBox.text: 'default' }"/>
<mx:Label text="conditional (value): { (flagBox2.selectedItem == 'a')? txtBox.text: 'default' }"/>
Checking flagBox will result in label #2 displaying "default" otherwise the text from the txtBox is displayed.
Selecting "a" in flagBox2 will result in label #3 displaying "default" otherwise the text from the txtBox is displayed.
I regularly use this for reducing my lines of code in my UI-logic and it works quite well for me. A problem of this techniques is that you can't use all logic symbols in curly-braket-bindings, such as < or &&, but i usually could life with that.

Related

Using a ComboBox as ItemEditor in Flex 4

I have a simple DataGrid with data. Of one of the columns, I want to use a ComboBox to edit the field, instead of the standard edit box.
How do I do that? I have tried all kind of things I found on the internet, but they all fail in simply updating the value. I'd say it shouldn't be too hard to do this.
I'm actually in the process of doing this myself, and with the spark:DataGrid it actually gets a bit easier than halo - but both follow the same setup / architecture.
Start with:
spark.components.gridClasses.ComboBoxGridItemEditor;
Depending on the nature of your data setup and/or how prolific this kind of editing will be for your application, you can write it inline as most documentation will suggest within a <fx:component>, or simply subclass this (although behind the scenes these are the same thing - the later being much easier to reuse). The data for the combo in my scenario is a sub selection of a bigger parent object, so I chose to make it easier on myself and add an additional property dataField to mimic other renderer / editors - in what actually shows in just the cell itself (when not in editing mode).
A basic setup looks something more or less like this (at least mine does):
public class AccountComboEditor extends ComboBoxGridItemEditor
{
private _dataField:String;
public function AccountComboEditor()
{
super();
//note - typically you wouldn't do "logic" in the view but it's simplified as an example
addEventListener(FlexEvent.CREATION_COMPLETE, onCreationComplete);
}
public function get dataField():String { return _dataField; }
public function set dataField(value:String):void
{
if (_dataField !=value) //dosomeadditionalvalidation();
_dataField = value;
}
override public function prepare():void
{
super.prepare();
if (data && dataField && comboBox) comboBox.labelField = data[dataField];
}
protected function onCreationComplete(event:FlexEvent):void
{
//now setup the dataProvider to your combo box -
//as a simple example mine comse out of a model
dataProvider = model.getCollection();
//this isn't done yet though - now you need a listener on the combo to know
//what item was selected, and then get that data_item (label) back onto this
//editor so it has something to show when the combo itself isn't in
//editor mode
}
}
So the real take away is to setup the labelField of the combobox, either internally in the subclass or externally if you need to expose it as an additional property.
The next part is to use this as part of the mx.core.ClassFactory for the actual data grid. A simple view would look like something similar:
<s:DataGrid>
<fx:Script>
private function getMyEditor(dataField:String):ClassFactory
{
var cf:ClassFactory = new ClassFactory(AccountComboEditor);
cf.properties = {dataField : dataField };
return cf;
}
</fx:Script>
<s:columns>
<mx:ArrayList>
<s:GridColumn itemEditor="{getMyEditor('some_data_property')}" />
</mx:ArrayList>
</s:columns>
</s:DataGrid>
This Creating item renderers... doc will give you more info.
I figured it out. I just wanted a simple drop down box, instead of a text-editing field.
The following code does want I want:
<mx:DataGridColumn dataField="type" headerText="Type" editorDataField="value">
<mx:itemEditor>
<fx:Component>
<mx:ComboBox>
<mx:dataProvider>
<fx:String>Gauge</fx:String>
<fx:String>Graph</fx:String>
<fx:String>Indicator</fx:String>
</mx:dataProvider>
</mx:ComboBox>
</fx:Component>
</mx:itemEditor>
</mx:DataGridColumn>

Is it possible to specify individual fonts in Flex DropDownList?

I have just implemented a dropdownlist of checkboxes taken from this ComboCheck example but made it extend DropDownList instead of ComboBox to provide better functionality that I required. I am attempting to create a DropDownList where some items are bold and non-checkboxes (or can be checkboxes) and others are not.
I have not been able to find anything online about doing this yet and have been trying to figure it out. I am currently using an ArrayCollection as a dataProvider but I think this could possibly be my issue and I should be trying to setup the labels in flex not AS3.
Does anyone know if this is possible? And if so do they have any links that could possibly help point me in the right direction?
Thanks.
EDIT: Code added for the itemRenderer, this worked I just need to specify each item that I want to be bold, though is there a better way to do this in the flex code as opposed to checking for a matching string in the renderer?
public class ComboCheckItemRenderer extends ItemRenderer{
public var item:CheckBox;
public function ComboCheckItemRenderer(){
super();
item = new CheckBox();
item.x = 5;
addElement(item);
item.addEventListener(MouseEvent.CLICK, onClick);
}
private var _data:Object;
[Bindable]override public function set data (value:Object):void {
if (value!=null) {
_data = value;
item.label = value.label;
if(item.label == "item1"){
item.setStyle("color","0x00ff00");
item.setStyle("fontWeight","bold");
}
item.selected = value.selected;
}
}
Edit 2: What I am ultimately trying to do is create a dropdown of checkboxes with data that I obtain from blazeDS that basically has a bunch of group titles and their corresponding sub-elements. I am trying to have the dropdown make the groups be in bold and to the left, and their sub-elements normal font and offset to the right. I also need to know when they are clicked whether it was a group header or sub-element, so that I can add them to an object that I will be sending back to my service to perform a sql query on.
ie.
[ ]**GROUP**
[ ] element
[ ] element
[ ]**GROUP**
[ ] element
What does your data look like? Why aren't you using MXML for this? Why are you overriding set data() as opposed to hooking the dataChange event? You are writing way more code than you need to here.
Lets look at it in a more "Flexy" way. Notice how I am using data binding for everything and conditionally setting the fontWeight based on the data that comes in. Anything more complicated should bust out to a function in the Script tag.
<?xml version="1.0" encoding="utf-8"?>
<s:ItemRenderer xmlns:fx="http://ns.adobe.com/mxml/2009"
xmlns:s="library://ns.adobe.com/flex/spark"
xmlns:mx="library://ns.adobe.com/flex/mx"
autoDrawBackground="true">
<fx:Script>
<![CDATA[
protected function onClick(event:MouseEvent):void {
}
]]>
</fx:Script>
<s:CheckBox x="5" click="onClick(event)"
label="{data.label}" selected="#{data.selected}"
fontWeight="{data.label == 'item1' ? 'bold' : 'normal'}"/>
</s:ItemRenderer>
In light of your question you added in your edit, I would ask: What criteria are you using? You can put any function in your binding expression, so at a very minimum, you might do something like this:
<fx:Script>
<![CDATA[
private var itemsToBold:Array = ["label1", "label2"];
private function getFontWeight(label):String {
if(itemsToBold.indexOf(label) > 0)
return "bold";
return "normal";
}
]]>
</fx:Script>
<s:CheckBox fontWeight="{getFontWeight(data.label)}"/>

ArrayCollection Objects to String - Problems with "for each" loop

This is related to other question. But never mind it. I've fixed part of it.
I have a DataGrid, its data provider is a ArrayCollection, and i want it to parse all itens in it (Object Type) to a String.
For that I've done a "for each" loop, it manages to get the Object and its values, but if i have more that one object it only gets the last object, don't know why.
First i will show how these items are added to the ArrayCollection, that way you will understand the rest much easily.
In the Main Application i have the ArrayCollection:
<mx:ArrayCollection id="collection">
Then in other Component there is a Add Item Menu, and when you add a item:
private function fazerEncomenda():void
{
var novoitem:Object;
novoitem = new Object();
novoitem.id = "consumivel"+getProdInfo.lastResult.consumivel.id;
novoitem.tinteiroid = getProdInfo.lastResult.consumivel.id;
novoitem.label = getProdInfo.lastResult.consumivel.nome;
novoitem.ref = getProdInfo.lastResult.consumivel.refmarca;
novoitem.marca = getProdInfo.lastResult.consumivel.marca;
novoitem.genero = genero.text;
novoitem.quantidade = quantidade.text;
Application.application.collection.addItem(novoitem);
}
Then in another component the DataGrid as its dataProvider Binded to the ArrayCollection
<mx:DataGrid id="compras" x="0" y="0" width="556" dataProvider="{Application.application.collection}" editable="false">
<mx:columns>
<mx:DataGridColumn headerText="ID" dataField="tinteiroid" visible="false"/>
<mx:DataGridColumn headerText="Nome" dataField="label" width="120" />
<mx:DataGridColumn headerText="Ref" dataField="ref" width="100"/>
<mx:DataGridColumn headerText="Marca" dataField="marca" width="100"/>
<mx:DataGridColumn headerText="GĂ©nero" dataField="genero" width="155"/>
<mx:DataGridColumn headerText="Quantidade" dataField="quantidade" width="81"/>
</mx:columns>
</mx:DataGrid>
And when a Button is pressed the function to get all Objects and its values to an String.
And in this function its where it only gets the last item, in the ArrayCollection.
for each (novoitem in compras.dataProvider)
{
finish += "TinteiroID:"+novoitem.tinteiroid+"#TinteiroLABEL:"+novoitem.label+"#TinteiroREF:"+novoitem.ref+"#TinteiroMARCA:"+novoitem.marca+"#TinteiroGENERO:"+novoitem.genero+"#TinteiroQUANTIDADE:"+novoitem.quantidade+"#FIMPROD#";
trace(finish);
}
And of course the Vars used in the function:
private var finish:String;
private var novoitem:Object
As you see in the finish var i used += so it adds it self and the next object. Instead he adds null. And only one null event if there was 3 items before.
Don't know whats the problem with this loop.
Please Help. I'm loosing my mind here.
PS: Sorry for any bad English, its been 3 hours in this. And no progress.
EDIT: Missing Vars Declaration Added
An easier way to do all this (admittedly not with the labels you specified) is to just use ActionScript's built in ObjectUtil.toString method.
You would write something like this:
import mx.utils.ObjectUtil;
public function dumpObj():void {
myTextField.text = ObjectUtil.toString(obj);
}
This should pretty much print out every property of every multiple / nested object you have.
HOWEVER - you should make a fundamental change to your component if you want it to be reusable. You need a getter/setter for your collection. In the component, add this code:
[Bindable]
private var _myCollection:ArrayCollection;
public function set myCollection (data:ArrayCollection) : void {
_myCollection = data;
}
public function get myCollection () : ArrayCollection {
return _myCollection;
}
There are several other ways to do this - look it up if you need something different.
In your datagrid, use the private ArrayCollection variable like this:
<mx:DataGrid id="compras" x="0" y="0" width="556" dataProvider="{_myCollection}" editable="false">
<mx:columns>
<mx:DataGridColumn headerText="ID" dataField="tinteiroid" visible="false"/>
...
In the main application, you can populate your component like this:
<kgtm:myComponent x="0" y="20" myCollection="{queryDataAC}"
And you name your ArrayCollection like this:
<mx:ArrayCollection id="queryDataAC">
in your top level Application code, you define the kgtm namespace, so you can use your custom component, like so:
<s:Application xmlns:fx="http://ns.adobe.com/mxml/2009"
xmlns:s="library://ns.adobe.com/flex/spark"
xmlns:kgtm="com.kgtm.*"
Then put your component in the folder corresponding to this namespace definition.
This all leads to the final object print utility - which you define on the component, as it is the only thing that should know about how to print out it's data.
Define a public function, and get it to print out the private ArrayCollection data, using ObjectUtil or your own method.
public var getLastQueryOutput () : String {
private var output:String = "";
private var len:int = _myCollection.length;
for (var i:int = 0; i <len; i++) {
output = output +
"TinteiroID:"+_myCollection[i].tinteiroid+
"#TinteiroLABEL:"+_myCollection[i].label+
"#TinteiroREF:"+_myCollection[i].ref+
"#TinteiroMARCA:"+_myCollection[i].marca+
"#TinteiroGENERO:"+_myCollection[i].genero+
"#TinteiroQUANTIDADE:"+_myCollection[i].quantidade+
"#FIMPROD#";
}
trace(output);
}
Hopefully this will help. If you name the object correctly as you are putting it into the ArrayCollection, you can again just use ObjectUtil as I stated at the top.
Casp - Check out more of my (and my colleagues) blog entries here
Have you tried ".source" property of your array collection? I'm not sure if for-each loops work on ArrayCollection objects.
e.g.,
for each(novoitem in compras.dataProvider.source) { ... }
have you tried to just use a regular for loop
for (var i:int = 0; i < compras.dataProvider.length; i++) {
novoitem= compras.dataProvider[i];
trace(novoitem); // will output to the console during debugging.
...
}
in any case you shouldn't be looping on the dataProvider you sould be looping on the Application.application.collection
Guys i really want to thank you.
Thanks to your effort Glenn and AndrewB i did it. Once again thanks.
Now i will post the code so that someone with a similar problem can get some help.
Here goes the code to get the Objects and the Itens for each object inside a ArrayCollection.
[Bindable]
private var finish:String = "";
private var novoitem:Object
for (var i:int = 0; i <Application.application.collection.length; i++)
{
novoitem = compras.dataProvider[i];
finish = finish + "TinteiroID:"+novoitem.tinteiroid+"#TinteiroLABEL:"+novoitem.label+"#TinteiroREF:"+novoitem.ref+"#TinteiroMARCA:"+novoitem.marca+"#TinteiroGENERO:"+novoitem.genero+"#TinteiroQUANTIDADE:"+novoitem.quantidade+"#FIMPROD#";
trace(finish);
}
Thanks once again. I wanted to place both your awnsers as correct, but they aren't completely. So I've combined both to this code. And here it is.
I will be signing this answer as correct, but the credit its all yours. I wouldn't have it done if it weren't with you help.
EDIT
This is the code I've used however take a look at the code that "CaspNZ" as posted. Its probably a better and lighter approach in performance.

Flex - Sending a parameter to a custom ItemRenderer?

What I am trying to accomplish to to get financial data in my Flex Datagrid to be color-coded--green if it's positive; red if it's negative. This would be fairly straightforward if the column I want colored was part of the dataProvider. Instead, I am calculating it based on two other columns that are part of the dataProvider. That would still be fairly straightforward because I could just calculate it again in the ItemRenderer, but another part of the calculation is based on the value of a textBox. So, what I think I need to be able to do is send the value of the textBox to the custom ItemRenderer, but since that value is stored in the main MXML Application, I don't know how to access it. Sending it as a parameter seems like the best way, but perhaps there's another.
Here is the current code for my ItemRenderer:
package {
import mx.controls.Label;
import mx.controls.listClasses.*;
public class PriceLabel extends Label {
private const POSITIVE_COLOR:uint = 0x458B00 // Green
private const NEGATIVE_COLOR:uint = 0xFF0000; // Red
override protected function updateDisplayList(unscaledWidth:Number, unscaledHeight:Number):void {
super.updateDisplayList(unscaledWidth, unscaledHeight);
/* Set the font color based on the item price. */
setStyle("color", (data.AvailableFunding >= 0) ? NEGATIVE_COLOR : POSITIVE_COLOR);
}
}
(data.AvailableFunding doesn't exist)
So does anyone know how I would go about accomplishing this?
You may want to look into ClassFactory from the Flex APIs:
This allows you to set a prototype Object with arbitrary types / values each of which will be passed to the item renderer. From the sample:
var productRenderer:ClassFactory = new ClassFactory(ProductRenderer);
productRenderer.properties = { showProductImage: true };
myList.itemRenderer = productRenderer;
The above code assumed that "ProductRenderer" has a public property called "showProductImage" which will be set with a value of "true."
Ah, so I knew about outerDocument but not parentDocument. I was able to just use parentDocument.*whatever I want from the main App and I can access it as long as it's public.
Example:
setStyle("color", (parentDocument.availableFunding >= 0) ? POSITIVE_COLOR : NEGATIVE_COLOR);
Sweet! :)
You can access the value of the TextBox directly, if you need to, by using the static Application.application object, which is accessible from anywhere in your application.
For example, if you wanted the renderers to be notified when the value of the TextInput control changes, you could do something like this (from within your ItemRenderer, and where myTextInput is the ID of the control defined in your main MXML class):
<mx:Script>
<![CDATA[
import mx.core.Application;
private function creationCompleteHandler(event:Event):void
{
Application.application.myTextInput.addEventListener(TextEvent.TEXT_INPUT, handleTextInput, false, 0, true);
}
private function handleTextInput(event:TextEvent):void
{
if (event.currentTarget.text == "some special value")
{
// Take some action...
}
}
]]>
</mx:Script>
With this approach, each item-renderer object will be notified when the TextInput's text property changes, and you can take appropriate action based on the value of the control at that time. Notice as well that I've set the useWeakReference argument to true in this case, to make sure the listener assignments don't interfere unintentionally with garbage collection. Hope it helps!
There's another technique, which, while it initially feels a little hacky is perhaps less cumbersome and cleaner in actual use.
It involves the little-observed fact that an event dispatch is, of course, synchronous and the event object can be treated as a value object populated by any event handler.
i.e. the ItemRenderer can do something like:
...
var questionEvt:DynamicEvent = new DynamicEvent('answerMeThis', true, true);
if (dispatchEvent(questionEvt))
{
if (questionEvent.answer == "some value")
....
With a corresponding handler somewhere up the view hierarchy above the renderer that has a listener on the event and does something like:
function handleAnswerMeThis(event:DynamicEvent):void
{
event.answer = "another value";
event.dataHelper = new DataHelperThingy();
}
etc.
It need not be a DynamicEvent - I'm just using that for lazy illustrative purposes.
I vote up for cliff.meyers' answer.
Here's another example on setting the properties of an itemRenderer from MXML by building a function that wraps a ClassFactory around the itemRenderer class and that injects the necessary properties.
The static function:
public static function createRendererWithProperties(renderer:Class,
properties:Object ):IFactory {
var factory:ClassFactory = new ClassFactory(renderer);
factory.properties = properties;
return factory;
}
A simple example that adds a Tooltip to each item in a list:
<mx:List dataProvider="{['Foo', 'Bar']}" itemRenderer="{createRendererWithProperties(Label, {toolTip: 'Hello'})}"/>
Reference:
http://cookbooks.adobe.com/post_Setting_the_properties_of_an_itemRenderer_from_MXM-5762.html
You use outerDocument property. Please see the fx:Component reference.
You could create an 'AvailableFunding' static variable in the ItemRenderer and then set it in the parent document.
public class PriceLabel extends Label {
public static var availableFunding:int;
...
...
SetStyle("color", (PriceLabel.availableFunding >= 0) ? NEGATIVE_COLOR : POSITIVE_COLOR);
}
In your parent document, set it when your text box gets updated
PriceLabel.availableFunding = textBox.text;
Obviously it'll be the same value for every ItemRenderer but it looks like that might be what you're doing anyway.
I like to override the set data function of the item renderer to change the renderer when the data provider changes as shown here
When you override the function you could cast the object to your object to make the availableFunding property available.
To access the text box you could try creating a public property and binding the property to the text box in the mxml file:
public var textVar:String;
<mx:itemRenderer>
<mx:Component>
<customrenderer textVar="{txtBox.text}" />
</mx:Component>
</mx:itemRenderer>
Nice ClassFactory Example here
See this example:
itemRenderer="{UIUtils.createRenderer(TextBox,{iconSrc:IconRepository.linechart,headerColor:0xB7D034,subHeaderColor:0xE3007F,textColor:0x75757D})}"

Flex: Determine if a component is showing

What is the best way to determine if a component in Flex/Flash is showing on the user's screen? I'm looking for an analog to Java's Component.isShowing() method.
The show and hide events fire for visibility, and this seems to work for the first descendant of a ViewStack component, but not further down the display tree.
... or avoiding recursion:
public static function isVisible(obj:DisplayObject):Boolean
{
while (obj && obj.visible && obj !== Application.application)
{
obj = obj.parent;
}
return obj && obj.visible;
}
You want to check if the component property visible is true and this is for all the parents of your component in the DisplayList, am I correct?
public static function isVisible(c : UIComponent) : Boolean {
if (c == null) return false;
if (c is Application) return c.visible;
return c.visible && isVisible(c.parent);
}
UIComponent.visible is not necessarily valid for children of an object where visible=false. From the docs:
"In either case the children of the object will not emit a show or hide event unless the object has specifically written an implementation to do so."
I wrote a sample application that confirms this to be true. What you can do is walk up the display list checking for visible to be false on a parent. Basically "visible" gives false positives but shouldn't give false negatives. Here is a quick utility I put together:
package
{
import flash.display.DisplayObject;
import mx.core.Application;
public class VisibilityUtils
{
public static function isDisplayObjectVisible(obj : DisplayObject) : Boolean {
if (!obj.visible) return false;
return checkDisplayObjectVisible(obj);
}
private static function checkDisplayObjectVisible(obj : DisplayObject) : Boolean {
if (!obj.parent.visible) return false;
if (obj.parent != null && !(obj.parent is Application))
return checkDisplayObjectVisible(obj.parent);
else
return true;
}
}
}
I haven't done anything more than trivial tests on this but it should get you started.
Strange as it seems, now that you mention it, I don't believe there is a simple test to determine whether a component is actually visible onscreen in the sense Component.isShowing() implies.
It's also true the show and hide events don't bubble by default, so if you want to be notified of visibility changes in a descendant of a ViewStack container, you'll need to listen for them explicitly. The implementation details would vary depending on what sort of behavior you were after, but to take the simple example:
<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" layout="absolute">
<mx:VBox>
<mx:HBox>
<mx:Button id="btn1" click="vs.selectedIndex = 0" label="Show 1" />
<mx:Button id="btn2" click="vs.selectedIndex = 1" label="Show 2" />
</mx:HBox>
<mx:ViewStack id="vs" selectedIndex="0">
<mx:Panel id="panel1">
<mx:Label id="label1" text="Label 1" show="trace('showing label 1')" hide="trace('hiding label 1')" visible="{panel1.visible}" />
</mx:Panel>
<mx:Panel id="panel2">
<mx:Label id="label2" text="Label 2" show="trace('showing label 2')" hide="trace('hiding label 2')" visible="{panel2.visible}" />
</mx:Panel>
</mx:ViewStack>
</mx:VBox>
</mx:Application>
... you'll see the show and hide events for each label fire once their visible properties have been bound to their parent panels'. Hopefully that illustrates the point; you can extend it however best suits your application. Good luck!
I was trying to obtain the same in a reusable manner.. I almost found out a way using getObjectsUnderPoint() - this returns the object under a particolar point, z-ordered (even if they are not siblings, e.g. ViewStack, Popups, ecc.).
Basically, I get the topmost display object on under a particular point of the stage, then go up un the display object hierarchy to find the tested object. If I find it, the object is visible (not visible objects in the hierarchy should be already filtered out by the getObjectsUnderPoint call).
The problem here is that you must use a non-transparent point of your object (in my case, I used an offset of 5 pixel due to rounder borders), otherwise it will not be picked up by this function.
Any ideas to improve it?
Cosma
public static function isVisible(object:DisplayObject):Boolean {
var point:Point = object.localToGlobal(new Point(5, 5));
var objects:Array = object.stage.getObjectsUnderPoint(point);
if (objects.length > 0) {
if (isDescendantOf(object, objects[objects.length - 1] as DisplayObject)) {
return true;
}
}
return false;
}
public static function isDescendantOf(parent:DisplayObject, child:DisplayObject):Boolean {
while (child.parent != null) {
if (child.parent === parent) {
return true;
} else {
child = child.parent;
}
}
return false;
}
This is all you really need. The "Application.application" check is futile.
/**
* Returns `true` if this component is actually shown on screen currently. This could be false even with
* "visible" set to `true`, because one or more parents could have "visible" set to `false`.
*/
public static function isShowing (c : DisplayObject) : Boolean {
while (c && c.visible && c.parent) {
c = c.parent;
}
return c.visible;
}

Resources