How to draw to a sprite outside of a class - apache-flex

I'm wondering (based on scoping rules) how I might do the following:
I want to draw to a sprite that exists on the main stage in which I have a class instantiated.
So something like
public function MyClass(reference:String){
this.reference = reference;
}
public function drawToOutsideSprite(){
this.parent.getChildByName(this.reference).addChild(someLoaderName);
}
Would I use super() in this case, or what's the usual methodology?
Thanks,
jml

There are a few ways to do this. I'm assuming your MyClass extends Sprite.
package
{
import flash.display.DisplayObject;
import flash.display.DisplayObjectContainer;
import flash.display.Sprite;
/**
* MyClass
*/
public class MyClass extends Sprite
{
public var referenceA:String;
public var referenceB:Sprite;
public function get referenceA_way2():Sprite
{
return this.parent.getChildByName(referenceA);
}
/**
* MyClass Constructor
*/
public function MyClass(referenceA:String = null, referenceB:Sprite = null)
{
super();
this.referenceA = referenceA;
this.referenceB = referenceB;
}
public function drawToOutsideSpriteA(child:DisplayObject):void
{
// referenceA
this.parent.getChildByName(this.referenceA).addChild(child);
// or
referenceA_way2.addChild(child);
}
public function drawToOutsideSpriteB(child:DisplayObject):void
{
// referenceB
referenceB.addChild(child);
}
public function drawToOutsideSpriteC(referenceC:String, child:DisplayObject):void
{
this.parent.getChildByName(referenceC).addChild(child);
}
// Do this:
// it allows you to abstract out the logic of getting the main sprite
// into some util class, so you could reuse that functionality elsewhere,
// and so your code is cleaner.
public function drawToOutsideSpriteD(child:DisplayObject):void
{
StageUtil.getMainSprite().addChild(child);
}
}
}
package
{
import flash.display.DisplayObject;
import flash.display.DisplayObjectContainer;
import flash.display.Sprite;
/**
* MyClass
*/
public class StageUtil
{
private static var root:Stage;
/**
* Called when app first starts
*/
public static function initialize(stage:Stage):void
{
root = stage;
}
public static function getMainSprite():DisplayObjectContainer
{
return root; // or something more complex,
// like a recursive function to getSpriteByName
}
public static function addToStage(child:DisplayObject):DisplayObject
{
return getMainSprite().addChild(child);
}
}
}
In general I would abstract out the logic for getting the "main" sprite into some util/manager class, because you don't want to hardcode that into your MyClass, as you might need it in other places, and you might want to customize it later on. It sounds like your just asking what's the best way to reference sprites outside of the scope of the MyClass, so I say just put it into the Util, assuming it has good reason for being their (like FlexGlobals.topLevelApplication in Flex, so you can easily access the application).
I don't recommend passing in id's or name's into the constructor and doing it that way, I don't really recommend constructor arguments at all. I would just pass those into a method if you needed to, or have it built into the class itself, or the Util.
To clear up the scoping question a little... You normally don't want to draw to sprites outside the scope of the class you are in, unless they have some special functionality that will be referenced by multiple classes with totally different scopes. This is because things would start not making sense, who's being added to who. But some good examples on when to do thatinclude:
Buttons with ToolTips: Tooltips are added to the root because they appear on top of everything, but a Button could be 20 children deep, so you'd have in the Button subclass, perhaps, addToolTip(child).
PopUps: You might want to add a popup from within MyClass, but it's really being added to the stage. In flex this is like PopUpManager.addPopUp(child), just like the sample StageUtil.getMainSprite().addChild(child). You could even wrap that method so it's like the one in the class above, addToStage.
Transform/Drawing Stage: If you have some global painting stage, or place where you scale/resize things, you might want to be able to add/remove graphics from that from any class.
The super() method isn't useful in this scenario. The only time you really use super() is if you have overridden a method, and want to access the super-classes implementation. Something like this (assuming you're extending Sprite):
override public function addChild(child:DisplayObject):DisplayObject
{
if (child is MyDrawingSprite)
return StageUtil.addToStage(child); // add to main stage
else
return super.addChild(child); // add directly to this class
}
Otherwise, try to stick to just adding children directly to the "MyClass".
Hope that helps.

Related

How to get different singleton in different module that create the same singleton in Flex?

I had study 「Beware of singleton in Flex modules」
in http://www.devahead.com/blog/2010/03/beware-of-singleton-in-flex-modules/
and a lot of information tell me that different module with different content,but in my case it doesn't work!
why the different module use the same static object?
I'm trying to use module wide singleton,but it work like application wide singleton.
Can someone help me how to make module wide singleton.
the short code is like:
<s:Application>
<s:ModuleLoader id="A" creationComplete="loadAModule()"/>
<s:ModuleLoader id="B" creationComplete="loadBModule()"/>
</s:Application>
//-----------AModule
<s:Module>
var aITx:ITx=Tx.newInstant();//Tx extend ITX
tracc(aITx.instantId);
...
</s:Module>
//-----------BModule
<s:Module>
var aITx:ITx=Tx.getInstance();//Tx extend ITX
tracc(aITx.instanceID);
...
</s:Module>
//-----singleton class
public class Tx extends EventDispatcher implements ITx
{
public function Tx()
{
// Add listeners
addEventListeners();
}
private static var instance:Tx;
public static function getInstance():Tx
{
if (!instance)
{
instance = new Tx();
// Generate a random instance ID
instance._instanceID = Math.round(Math.random() * 100);
trace("create new itx id="+instance.instanceID);
}else{
trace("use old itx id="+instance.instanceID);
}
return instance;
}
protected var _instanceID: Number = NaN;
public function get instanceID(): Number
{
return _instanceID;
}
}
I think your problem is related to the context the modules are loaded in. In your case I guess all of your modules are loaded into the same context. In one context there is only one version of one class. Therefore there is only one instance of your Singleton. If you want to have separate classes, you have to load each module into its own context. Have a look at this link which explains the context stuff pretty good: http://livedocs.adobe.com/flex/3/html/help.html?content=05_Display_Programming_33.html

Flex - how to detect if Object DATA has changed?

In Flex (Flash Builder 4), I need a way to know if something in an array collection has changed.
I have a custom object:
[Bindable]
public var _myobject:MyObject;
It's basically just a class containing a bunch of different String and Number properties.
I need a reliable way to know if any of the properties have been changed. For example, I am binding the properties to a user interface (fields), but it's also possible for some of the properties to change through code.
Is there a way to do this? I found ChangeWatcher, but that looks like it only looks at a single simple property, such as a String or Number. I need to watch or detect changes in all the properties in my object, hopefully without having to add ChangeWatcher events to every property. Is this possible?
You're probably better off just dispatching binding events on the specific properties you want bindable. Better yet, dispatch a custom binding event, so that all of the things that are bound don't have to filter for "is this the property I care about?" It's really easy with Flash Builder 4.5 to do this, just select your variable name and press Ctrl-1, select "Create getter and setter," select getter and setter and check "Bindable" and "create custom event."
This will create code for you that looks something like this:
private var _yourProperty:String;
[Bindable (event='yourPropertyChange')]
public function get yourProperty():String {
return _yourProperty;
}
public function set yourProperty(value:String):void {
if (value !=== _yourProperty) {
_yourProperty = value;
dispatchEvent(new Event('yourPropertyChange'));
}
}
This will be much less verbose and more performant than the code that Flash Builder generates for you behind the scenes when you just use the Bindable tag on its own.
If you use defined classes as VO/DAO and apply the [Bindable] tag to the class, this will do binding on all properties for you (so long as they are read/write).
Anonymous object detection is difficult at best, let alone adding additional headaches of loosing compiler type checking.
Super basic example: - the key is to tie it to the dispatcher, so internally it can send out the PropertyChangeEvent.
[Bindable]
public class Actor extends EventDispatcher
{
public var fName:String;
public var lName:String;
public var age:uint;
public function get displayName():String
{
return lName +', '+ fName;
}
public function Actor()
{
super();
}
}
public class BindableDictionary extends EventDispatcher {
public function BindableDictionary() {
super();
}
public var dictionary:Dictionary = new Dictionary();
[Bindable("change")]
public function get(key:Object):Object {
return dictionary[key];
}
public function put(key:Object, value:Object):void {
dictionary[key] = value;
dispatchEvent(new Event(Event.CHANGE));
}
}
maybe this class will give you some new idea

How do I addEventListener to custom actionscript class?

I have an actionscript class MyClass that extens NavigatorContent. I instantiate the class as a custom MXML NavigatorContnent component for an Accordion component. MyClass has a Button component that I have tried to attach an event listener to. I want the event to bubble so that I can have the handler in the Accordion component.
MyClass
package comp
{
import flash.events.Event;
import flash.events.MouseEvent;
[Event(name="selectEvent", type="flash.events.Event")]
public class MyClass extends NavigatorContent
{
public function MyClass()
{
super();
btnSelect.addEventListener(MouseEvent.CLICK, selectClickDispatcher);
}
public function selectClickDispatcher(event:MouseEvent):void
{
event.currentTarget.dispatchEvent(new Event("selectEvent",true));
}
}
}
From here I have the instantiated component nested in the Accordion. I am pretty sure the problem is in this class definition because when I set a breakpoint at the selectClickHandler, the code does not break. In case I am wrong I will post the rest of the components.
Custom component named MySubComp.mxml
<comp:MyClass
...I have a few more spark components here and nothing else...
/>
Accordion
<mx:Accordion>
<fx:Script> //omitted CDATA tags to save space
protected function selectEventHandler(event:Event):void
{
Alert.show("Value Selected");
}
</fx:Script>
//custom components are in the navs package
<navs:MySubComp selectEvent = "selectEventHandler(event)"/>
</mx:Accordion>
You have added the metadata to the class definition
[Event(name="selectEvent", type="flash.events.Event")]
so all you need to do in mxml is
<comp:MyClass selectEvent="event_handler(event)"
..... />
In AS3, you add an event listener by
myClass.addEventListener("selectEvent", event_handler);
P.S. Your class will have to extend EventDispatcher
Your class either needs to extend a DisplayObject class, or directly inherit from EventDispatcher in order to be able to use events. Forget about implementing IEventDispatcher as there's a special piece of black code somewhere that means that EventDispatcher is the only class that can set the target property of the Event class (I've tried it before).
Consider using other alternatives. Events in Flash tend to be slow and create objects all the time. Callbacks are a good system if you need something simple.
public class A
{
public var onSomething:Function = null;
public function foo():void
{
if( this.onSomething != null )
this.onSomething();
}
}
public class B
{
public function B()
{
var a:A = new A;
a.onSomething = this._somethingCalled; // set the callback
a.init();
}
private function _somethingCalled():void
{
trace( "hello there" );
}
}
You can also take a look at the Signals project: https://github.com/robertpenner/as3-signals/wiki
Signals are vastly superior to normal Flash events, and there's no restriction on the type of object that can use them (i.e. non-DisplayObject objects can still add event listeners and dispatch events). It's also faster and has a smaller memory footprint.
In case someone needs the real Actionscript-3 event dispatching to be used >>> this <<< is very helpful. I don't know if it is really slow but it meets the AS-3 standards.

Flex/Actionscript : passing data from custom class to main application?

Ok this probably sounds dumb but Im a complete beginner in Flex programming.
I have an application with a main .mxml file, and a certain class Foo that I call from the .mxml
In Foo, I make a URLRequest and listen for the Complete event. Then I found myself with the returned data in a Foo function, but I have no idea how to communicate it to the .mxml part of the applicaton ! I looked into ArrayCollections but I can't seem to understand how they work and whether it might help. Isn't there a way to modify, from inside the class, a variable with a global scope ?
This sounds like a small application, but if it's a large application you might want to look at a micro-framework like RobotLegs
If you have your Foo class extend EventDispatcher then it will be able to send events and have the main MXML app listen for said events.
package com.example
{
import flash.events.EventDispatcher;
import com.example.events.MyEvent;
public class Foo extends EventDispatcher
{
public function doAction():void
{
var someData:String = "blah";
dispatchEvent(new MyEvent(MyEvent.SOMETHING_HAPPENED, someData));
}
}
}
A Custom event with a payload (in this case a string)
package com.example.events
{
import flash.events.Event;
public class MyEvent extends Event
{
static public const SOMETHING_HAPPENED:String = "somethingHappened";
private var _myData:String;
public function get myData():String
{
return _myData;
}
public function MyEvent(type:String, myData:String, bubbles:Boolean=false, cancelable:Boolean=false)
{
_myData = myData;
super(type, bubbles, cancelable);
}
override public function clone():Event
{
return new MyEvent(type, myData, bubbles, cancelable);
}
}
}
Working with your Foo class from the main file:
public function EventDispatcherExample() {
var foo:Foo = new Foo();
foo.addEventListener(MyEvent.SOMETHING_HAPPENED, actionHandler);
foo.doAction();
}
private function actionHandler(e:MyEvent):void {
trace("my data is: " + e.myData);
}
import mx.core.FlexGlobals;
FlexGlobals.toplevelApplication.varName;
Your Foo class can dispatch an event and have something in you main.mxml listen for that event. I am sure that I could create an example. I think it is under customer events in Flex documentation. This is assuming I understand the question.
As John said, an event is your best choice.
If you'd like some example code, I provided some for a similar question here: Data from Popup to Main Application?
An event might be the best way to do it as it has been stated.
Another approach is to dispatch an event like this
dispatchEvent(new Event('somethingHappened'));
and also create a get method in your class for the data you need to get.
Then all you have to do in your main app is this
var foo:Foo = new Foo();
foo.addEventListener('somethingHappened', actionHandler);
private function actionHandler(e:Event):void
{
trace(foo.memberData);
}
This way might be more suitable if the data should be a class member anyway and if you would like to avoid creating a new event class.

What is the best way to associate an Event with a Class in ActionScript / Flex 3?

ActionScript 3 / Flex 3 - Adding custom events to a class
Say I have the following Event:
import flash.events.Event;
public class SomeEvent extends Event
{
public static const EVENT_ACTION:String = "eventAction";
public function SomeEvent(type:String) {
super(type);
}
override public function clone():Event {
return new SomeEvent(this.type);
}
}
... and the following Class:
public class SomeClass extends EventDispatcher
{
public function someFunction():void
{
dispatchEvent(new SomeEvent("eventAction"));
}
}
What is the best way to show that 'SomeClass' throws 'SomeEvent'? The only way I have found is to decorate 'SomeClass' with the [Event] attribute, as follows:
[Event (name="eventAction", type="SomeEvent")]
This allows me to instantiate the class and add an event listener by doing this:
var someClassInstance:SomeClass = new SomeClass();
someClassInstance.addEventListener(SomeEvent.EVENT_ACTION, mycallbackmethod);
Is there a better way to do this? Putting the [Event] attribute on the class followed by some string literals just feels ... wrong. Thanks in advance for the help!
You're doing it right. Currently, the AS3 compiler allows only string literals in metadata. Constants cannot be used.
By the way, Adobe's public bug database has a feature request to allow ActionScript constants in metadata. Feel free to vote for it.
I know, I feel the same way; using the string literals does seem a bit wrong somehow. But to the best of my knowledge, from all the documentation I've seen and the talks I've attended and in reading the Flex source code, etc., it does appear that's the proper way to do it.

Resources