Trying to use BindingUtils in Flash AS3.0 - actionscript-3

I am not able to make this code work in AS3.0 ( Flash ) with Flex SDK 4.0 included.
import mx.binding.utils.*;
[Bindable]
var myValue:int = 0;
var cw:ChangeWatcher = BindingUtils.bindSetter(myValueChanged, this, "myValue");
addEventListener( Event.ENTER_FRAME , ef);
function ef(e:Event):void
{
trace("hello",getTimer());
myValue = getTimer();
}
function myValueChanged(o:Object):void
{
trace("myValue: " + myValue.toString());
}
The output i get is :
myValue: 0
hello 157
hello 168
hello 171
hello 177
....
....
and so on.
But I expect the correct output should be :
myValue: 0
hello 157
myValue: 157
hello 168
myValue: 168
hello 171
myValue: 171
hello 177
myValue: 177
....
....
Thanks.

Data binding only works with Flex.
<?xml version="1.0" encoding="utf-8"?>
<s:WindowedApplication xmlns:fx="http://ns.adobe.com/mxml/2009"
xmlns:s="library://ns.adobe.com/flex/spark"
xmlns:mx="library://ns.adobe.com/flex/mx" enterFrame="ef(event)">
<fx:Declarations>
<!-- Place non-visual elements (e.g., services, value objects) here -->
</fx:Declarations>
<fx:Script>
<![CDATA[
import mx.binding.utils.*;
[Bindable]
public var myValue:int = 0;
private var cw:ChangeWatcher = BindingUtils.bindSetter(myValueChanged, this, "myValue");
private function ef(e:Event):void
{
trace("hello", getTimer());
myValue = getTimer();
}
private function myValueChanged(o:Object):void
{
trace("myValue: " + myValue.toString());
}
]]>
</fx:Script>
</s:WindowedApplication>

I'm not exactly sure how the Flash Pro compiler treats this stuff (I always use the free mxmlc compiler from the Flex SDK).
Does this work for you?
package
{
import flash.display.Sprite;
import flash.events.Event;
import flash.utils.getTimer;
import mx.binding.utils.BindingUtils;
public class BindingExample extends Sprite {
private var model:Model;
public function BindingExample()
{
model = new Model();
BindingUtils.bindProperty(this, 'spy', model, ['value']);
addEventListener( Event.ENTER_FRAME , onEnterFrame);
}
public function onEnterFrame(e:Event):void
{
model.value = getTimer();
}
public function set spy(value:int):void
{
trace('Bound property set to: ' + value);
}
}
}
class Model
{
[Bindable]
public var value:int;
}
If not, try this for the Model definition:
import flash.events.Event;
import flash.events.EventDispatcher;
class Model extends EventDispatcher
{
private var _value:int;
[Bindable("valueChange")]
public function get value():int
{
return _value;
}
public function set value(value:int):void
{
if (_value != value)
{
trace('Model property set to: ' + value);
_value = value;
dispatchEvent(new Event("valueChange"));
}
}
}
If that doesn't work, try this for the Model:
import flash.events.EventDispatcher;
import mx.events.PropertyChangeEvent;
import mx.events.PropertyChangeEventKind;
class Model extends EventDispatcher
{
private var _value:int;
[Bindable("propertyChange")]
public function get value():int
{
return _value;
}
public function set value(value:int):void
{
if (_value != value)
{
trace('Model property set to: ' + value);
var oldValue:int = _value;
_value = value;
dispatchEvent(new PropertyChangeEvent(
PropertyChangeEvent.PROPERTY_CHANGE, false, false,
PropertyChangeEventKind.UPDATE, "value", oldValue, value, this));
}
}
}
Or, perhaps with an ObjectProxy:
package
{
import flash.display.Sprite;
import flash.events.Event;
import flash.utils.getTimer;
import mx.binding.utils.BindingUtils;
import mx.utils.ObjectProxy;
public class BindingExample extends Sprite {
private var model:ObjectProxy;
public function BindingExample()
{
model = new ObjectProxy({value: 0});
BindingUtils.bindProperty(this, 'spy', model, ['value']);
addEventListener( Event.ENTER_FRAME , onEnterFrame);
}
public function onEnterFrame(e:Event):void
{
model.value = getTimer();
}
public function set spy(value:int):void
{
trace('Bound property set to: ' + value);
}
}
}
All of the above work fine when compiling with mxmlc. I'd avoid the ObjectProxy as it's the least typesafe.

You wrote:
I am not able to make this code work in AS3.0 ( Flash ) with Flex SDK 4.0 included.
I take it this means you are already using the mxmlc compiler, which is necessary for the Bindable metatag to work.
As I understand it, adding the Bindable meta tag to a variable is a way to listen for dispatches of a PropertyChangeEvent:
The Flex 4.6 API docs state:
[When using Bindable on a variable] The Flex compiler automatically generates an event named propertyChange, of type PropertyChangeEvent, for the property.
Basically a simpler way to do myValue.addEventListener(...)
So the variable we want to be Bindable must be of a type that extends EventDispatcher or implements IEventDispatcher. This is not the case with the primitive int which is the type of the variable you are trying to make bindable. Bindable on an int will not work.
To make it work you could wrap the int variable in a custom class BindableInteger that implements IEventDispatcher. Another options is to use ObjectProxy, which allows you to add EventListeners and make an object bindable even though it doesn't extend EventDispatcher or implements IEventDispatcher.
Also, note that you need to make your variable public, protected or private for Bindable to work.
Flex 4.6 docs on Using the Bindable meta tag:
You can use the [Bindable] metadata tag (...) [b]efore a public, protected, or private property defined as a variable to make that specific property support binding.
This will not work:
[Bindable] var myValue:int = 0;
but this will:
[Bindable] public var myValue:int = o;

Binding works for class properties, and doesn't work with local variables so you need to create the class:
package
{
import flash.display.Sprite;
import flash.events.Event;
import flash.utils.getTimer;
import mx.binding.utils.BindingUtils;
import mx.binding.utils.ChangeWatcher;
public class astest extends Sprite
{
[Bindable]
public var myValue:int = 0;
public function astest()
{
var cw:ChangeWatcher = BindingUtils.bindSetter(myValueChanged, this, "myValue");
addEventListener( Event.ENTER_FRAME , ef);
}
protected function ef(e:Event):void
{
trace("hello",getTimer());
myValue = getTimer();
}
protected function myValueChanged(o:Object):void
{
trace("myValue: " + myValue.toString());
}
}
}

Related

as3 calling a function in Main.as Document Class from another class

I am sure this is a popular question but I can't find the exact answer I need. I simply need to access a function or functions created in the Main.as document class. I have tried several methods and they do not seem to work. Here is one example I tried.
anotherClass.as // This needs to access functions Main.as
package com
{
import Main;
public class anotherClass
{
private var stageMain:Main;
public function anotherClass()
{
// tries to call a function in Main.as called languageLoaded. NO WORK!
stageMain.languageLoaded("English");
// in the Main.as languageLoaded is a public function
}
}
}
The cleaner way is to simply pass a reference to Main to the constructor of the class you want to be able to access it.
For example, your AnotherClass could look like this:
class AnotherClass
{
private var _main:Main;
public function AnotherClass(main:Main)
{
_main = main;
_main.test(); // Success!
}
}
And your main class:
class Main
{
public function Main()
{
var another:AnotherClass = new AnotherClass(this);
}
public function test():void
{
trace("Success!");
}
}
public class MainDoc extends MovieClip // as long as it extends eventDispatcher you re fine
{
private var otherClass:OtherClass;
public function MainDoc()
{
otherClass = new OtherClass();
otherClass.addEventListener("otherClassCustomEvent", onOtherClassReady);
otherClass.startLogic();
}
public function onOtherClassReady(event:Event = null)
{
trace("from other class:", otherClass.infoToShare) // traces "from other class: YOLO!"
}
}
public class OtherClass extends EventDispatcher // must extend the event dispatcher at least
{
public var infoToShare:String;
public function OtherClass()
{
}
public function startLogic()
{
// do what you got to do
// when you have your data ready
infoToShare = "YOLO!";
dispatchEvent("otherClassCustomEvent");
}
}
Once you're confortable with that, you can start looking into building custom events that could carry the variable to send back
Ok I got the following code to work. It's really a messy solution but I didn't know of a better way. It works. I just hope it's stable and does not use a lot of resources.
If you have a much better Idea I am open.
Here is the MainDoc.as
package {
import flash.display.MovieClip;
import flash.events.*;
import com.*;
import com.views.*;
import flash.display.*;
import flash.filesystem.*;
import com.greensock.*;
import com.greensock.easing.*;
import flash.system.System;
public class mainDoc extends MovieClip
{
/// (Get Main Doc flow) this creates an instace of the main timeline
/// and then I send it
private static var _instance:mainDoc;
public static function get instance():mainDoc { return _instance; }
/// Calls the defaultVars.as in to "vars".
var vars:defaultVars = new defaultVars();
public function mainDoc()
{
/// Makes this class ready to be passed to defautVars.as
_instance = this;
// Sends the _instance to defaulVars.as to be accessed later.
vars.getMainDoc(_instance);
// Calls a function in defaultVars.as and loads a var
vars.loadButtonVars("English");
}
}
}
Here is the defaultVars.as
package com {
import flash.display.Stage;
import flash.events.*
import flash.net.*;
import flash.display.*;
import flash.filesystem.*;
public class defaultVars
{
/// Makes the MainDoc.as a MovieClip
// Not sure if this is good but it works.
public var MainDoc:MovieClip;
public function defaultVars()
{
}
public function getMainDoc(_instance:MovieClip)
{
trace("CALLED" + _instance);
/// receives the _instance var and its converted to a MovieClip
// This can now be used in any function because I declared it a public var.
MainDoc = _instance;
}
public function loadButtonVars(Language:String)
{
myLoader.load(new URLRequest("Languages/" + Language + "/vars.xml"));
myLoader.addEventListener(Event.COMPLETE, processXML);
function processXML(e:Event):void
{
myXML = new XML(e.target.data);
/// Home Screen Buttons
homeT = myXML.Button.(#Title=="homeT");
homeB1 = myXML.Button.(#Title=="homeB1");
homeB2 = myXML.Button.(#Title=="homeB2");
homeB3 = myXML.Button.(#Title=="homeB3");
homeB4 = myXML.Button.(#Title=="homeB4");
homeB5 = myXML.Button.(#Title=="homeB5");
/// HERE IS WHERE I CALL FUNCTION from MainDoc after xml is loaded.
/////////////////
trace("xml loaded!!!! " + homeB1);
MainDoc.languageLoaded(Language);
}
}
}
}

Sharing variables in OOP AS3

In Main.as I have the following:
package {
import flash.display.MovieClip;
public class Main extends MovieClip {
public var damage:Number;
public function Main() {
// constructor code
var char:Character = new Character();
addChild(char);
}
}
}
And I have another package called Character.as
package {
import flash.display.MovieClip;
public class Character extends MovieClip{
public function Character() {
trace(damage);
}
}
}
I need to be able to share the damage set in the main.as with the character. Is there any way to make the speed more global?
Why don't you make damage a public property of your Character and then it'll be easily accessible via your Main class like this :
char.damage = 100;
trace (char.damage);
To do this, just add the property to your Character class like so :
public class Character extends MovieClip {
public var damage:Number;
public function Character() {
trace(damage);
}
}
But given your comment, I take it you would rather everything just be global and accessible everywhere as opposed to applying OOP concepts.
If so... just define it as a public static in your Main class like this :
public static var damage:Number;
and to access it anywhere you do this :
Main.damage = 100;
trace(Main.damage);
There is another way of sending values through packages (This way is not really sharing variables, but it could be useful for you). What this code does is that the class Character creates a variable, and this variables gets an value from the Main package:
Change the character.as to this:
package {
import flash.display.MovieClip;
public class Character extends MovieClip{
public function Character(a:int) {
//output will be the integer 10
trace(a);
}
}
}
and main.as to:
package {
import flash.display.MovieClip;
public class Main extends MovieClip {
private var damage:int = 10;
private var char:Character = new Character(damage);
public function Main() {
}
}
}
Edit: Not useful for realtime applications, because the values of private var damage will only be send on initialization of private var char:Character = new Character(damage).

In ActionScript 3.0, can you use addEventListener for one class to react to the function call of another class?

I know how to use addEventListener for one class to react to another class's button being clicked on. What if you want to use it for a more general purpose than that? What if you want to use it to react to one of the member functions of the other class being called? Is there a syntax for that? Thanks!
Edit: Please note that I have already Googled for the answer.
If you want to listen for another class' member function call, you need that function call to dispatch an Event. This is as simple as...
Listener Class
addEventListener("customEvent", listenerFunc);
Dispatcher Class (extends EventDispatcher / implements IEventDispatcher)
dispatchEvent(new Event("customEvent"));
As long as the listener class is above the dispatcher class in the object hierarchy, this will work perfectly. If not, you may want to use some sort of Global EventDispatcher class and register all listeners on that.
You can create your own events and dispatch them from the other class and listen to them in your listening class. Here is some code
In class A (assuming it inherits EventDispatcher)
public function classAMethod():void
{
dispatchEvent(new Event("someCustomTypeForEvent"));
}
In class B (assuming it has a reference to Class A)
public function classBMethod():void
{
classA.addEventListener("someCustomTypeForEvent",customHandler);
}
public function customHandler(e:Event):void
{
trace("handle event");
}
It's like in JAVA for java.awt.Component instances and all Objects that extends java.awt.Component; in AS3 you may add Listeners to all Objects that extends flash.display.Sprite instances which implements methods of IEventDispatcher for you...
So, If you have a class which do not extends flash.display.Sprite, you'll have to extend EventDispatcher in order to add Listeners to your instances and handle Events...
If the class may not extend EventDispatcher, you'll have to implement the IEventDispatcher.
Here is a [class MainClass] that extends [class MovieClip]
This MainClass instance, creates :
An instance of [class ObjectA] which extends [class Object] and implements IEventDispatcher,
An instance of [class ObjectB] which extends [class EventDispatcher]
Here is the code that use the extension method and the implementation method :
I hope this quick done example will help you...
(And sorry for my English, this is not my native language.)
in MainClass.as :
package com
{
import flash.utils.getDefinitionByName;
import flash.display.MovieClip;
import flash.utils.getDefinitionByName;
import flash.utils.getQualifiedClassName;
import flash.utils.getQualifiedSuperclassName;
import com.classes.ObjectA;
import com.classes.ObjectB;
import flash.events.Event;
public class MainClass extends flash.display.MovieClip
{
private static const DEBUG:Boolean = true;
private static var instance:MainClass;
private static var instanceOfA:ObjectA;
private static var instanceOfB:ObjectB;
public function MainClass()
{
MainClass.debug("MainClass constructor called");
MainClass.debug(getClassInformations(MainClass));
MainClass.debug(getClassInformations(ObjectA));
MainClass.debug(getClassInformations(ObjectB));
instanceOfA = new ObjectA();
instanceOfB = new ObjectB();
instanceOfA.addEventListener(ObjectA.DO_SOMETHING_EVENT,onInstanceOfA_doSomething,false,0,false);
instanceOfB.addEventListener(ObjectB.DO_SOMETHING_EVENT,onInstanceOfB_doSomething,false,0,false);
instanceOfA.doSomething();
instanceOfB.doSomething();
}
public static function onInstanceOfA_doSomething(e:Event):void
{
trace("An ObjectA has Dispatched An Event of type \"" + e.type + "\"" + " on " + e.target);
}
public static function onInstanceOfB_doSomething(e:Event):void
{
trace("An ObjectB has Dispatched An Event of type \"" + e.type + "\"" + " on " + e.target);
}
public static function getDebugMode():Boolean
{
return DEBUG;
}
public static function debug(string:String)
{
if (getDebugMode())
{
trace(string);
}
}
public static function getClassInformations(someClass:Class):String
{
var clss:Object = null;
var supClss:Object = null;
clss = getDefinitionByName(getQualifiedClassName(someClass));
try
{
supClss = getDefinitionByName(getQualifiedSuperclassName(someClass));
}
catch (e:ArgumentError)
{
// Has no superClass (ex:Object)
}
if (supClss != null)
{
return ("class " + clss + " extends " + supClss);
}
else
{
return ("class " + clss);
}
}
}
}
in ObjectB.as (simplest way):
package com.classes{
import com.MainClass;
import flash.events.EventDispatcher;
import flash.events.Event;
public class ObjectB extends EventDispatcher {
public static var DO_SOMETHING_EVENT:String = "do_something_event";
private var onDoSomethingEvent:Event = new Event(DO_SOMETHING_EVENT,false,false);
public function ObjectB() {
MainClass.debug("constructor ObjectB called");
}
public function doSomething():void{
this.dispatchEvent(onDoSomethingEvent);
}
}
}
in ObjectA.as (there you must implement all the methods of the interface IEventDispatcher):
package com.classes
{
import com.MainClass;
import flash.events.IEventDispatcher;
import flash.events.EventDispatcher;
import flash.events.Event;
public class ObjectA implements IEventDispatcher
{
public static var DO_SOMETHING_EVENT:String = "do_something_event";
private var onDoSomethingEvent:Event = new Event(DO_SOMETHING_EVENT,false,false);
private var dispatcher:EventDispatcher;
public function ObjectA()
{
dispatcher = new EventDispatcher(this);
MainClass.debug("constructor ObjectA called");
}
public function doSomething():void
{
this.dispatchEvent(onDoSomethingEvent);
}
public function addEventListener(
event_type:String,
event_listener:Function,
use_capture:Boolean = false,
priority:int = 0,
weakRef:Boolean = false
):void
{
// implements addEventListener here
dispatcher.addEventListener(event_type, event_listener, use_capture, priority, weakRef);
}
public function dispatchEvent(e:Event):Boolean
{
// implements dispatchEvent here
return dispatcher.dispatchEvent(e);
}
public function removeEventListener(
event_type:String,
event_listener:Function,
use_capture:Boolean = false
):void
{
// implements removeEventListener here
dispatcher.removeEventListener(event_type, event_listener, use_capture);
}
public function hasEventListener(type:String):Boolean
{
// implements hasEventListener here
return dispatcher.hasEventListener(type);
}
public function willTrigger(type:String):Boolean
{
// implements willTrigger here
return dispatcher.willTrigger(type);
}
}
}
Note that if you extend an EventDispatcher, you may also want to override some methods.
In this case, you must use the "override keyword as :
public override function dispatchEvent (e:Event):Boolean {
// a method of EventDispatcher may be overridden if needed !
// do what you need HERE...
return dispatchEvent(e);
}
In AS3 you must specify the override keyword or you'll get an Error 1024:
"Overriding a function that is not marked for override."
When you create a new EventDispatcher through implement or extend, you may also specify additional arguments and methods to this object as:
public function ListenerObject (v:View,m:Main) {
dispatcher = new EventDispatcher(this);
view = v;
master = m;
}
public function getView ():View {
return view;
}
public function getMain ():Main {
return master;
}
then use those methods in the callback method as :
public function callback(e:Event):void{
e.target.getView ();
//...
}

How do I tween a variable with TweenLite?

package
{
import com.greensock.TweenLite;
import flash.display.Sprite;
public class TweenTest extends Sprite
{
private var _test:Number = 10;
public function TweenTest()
{
TweenLite.to(this,1,{_test:200});
}
}
}
I get the error #1069: Property _test not found for TweenTest…
I also tried this example which does not work for me:
http://www.snorkl.tv/2010/09/how-to-tween-a-variable-with-flash-and-tweenlite/
TweenLite can only affect public properties of a class. Making _text public or creating an public getter should sort it out.
This is definitely possible by simply making your variable public.
You can also do something like:
var arr:Array = [0];
TweenLite.to(arr, 1, {endArray: [10], onUpdate: output});
function output():void
{
trace (arr[0]);
}

Need help understand MVC implementation within Actionscript 3 AS3, please

I am learning MVC implementation with ActionScript 3.0. So far, I have done alright but have couple of questions that can make this learning process very pleasant for me. I would highly appreciate your help and wisdom.
Let me explain how I am implementing a simple MVC implementation:
My Flash Movie is called FusionMVC. I have all the MVC files within the same package like this:
DataModel
DataControl
DataView
Application Facade
Here are my question:
As I understand it correctly, whenever I need to place a display object on the main stage, I declare or implement that display object in DataView class, am I right?
I have a symbol/display object called "Box" in the main library. I add this symbol to the stage by instantiating it within DataView class which I am able to see at runtime. Now if I need to add an EventListener called "ClickHandler" to this object:
Where do I declare this "ClickHandler" event, please? I am currently declaring it in the DataModel Class.
What I am confused about is to where to declare the EventHandler Methods. DataModel, or DataControl?
Thank you for your help. Here is the entire code:
//DATAMODEL
package
{
import flash.events.*;
import flash.errors.*;
public class DataModel extends EventDispatcher
{
public static const UPDATE:String = "modelUpdaed";
private var _txt:String;
public function DataModel()
{
}
public function get Text():String
{
return _txt;
}
public function set Text(p:String):void
{
_txt = p;
notifyObserver();
trace("MODEL HAS BEEN CHANGED");
}
public function notifyObserver():void
{
dispatchEvent(new Event(DataModel.UPDATE));
}
public function sayHello(e:Event):void
{
trace("HEY HELLO");
}
}
}
//DATACONTROL
package
{
import flash.display.*;
import flash.events.*;
import flash.errors.*;
public class DataControl
{
private var _model:DataModel;
public function DataControl(m:DataModel)
{
_model = m;
}
}
}
//DATAVIEW
package
{
import flash.display.*;
import flash.events.*;
import flash.errors.*;
public class DataView extends Sprite
{
private var _model:DataModel;
private var _control:DataControl;
public var b:Box;
public function DataView(m:DataModel, c:DataControl)
{
_model = m;
_control = c;
addBox();
}
public function addBox():void
{
b = new Box();
b.x = b.y = 150;
//b.addEventListener(MouseEvent.CLICK, vHandler);
addChild(b);
}
}
}
//APPLICATION FACADE
package
{
import flash.display.*;
import flash.events.*;
import flash.errors.*;
public class Main extends Sprite
{
private var _model:DataModel;
private var _control:DataControl;
private var _view:DataView;
public function Main()
{
_model = new DataModel();
_control = new DataControl(_model);
_view = new DataView(_model, _control);
addChild(_view);
}
}
}
You are correct - display objects should handle events from their own children:
public function addBox():void
{
b = new Box();
b.x = b.y = 150;
b.addEventListener(MouseEvent.CLICK, boxClickHandler);
addChild(b);
}
Handle the event in the view:
private function boxClickHandler(event:MouseEvent)
{
_control.sayHello();
}
And then you just need to add to your controller the method to change the model:
public class DataControl
{
....
public function sayHello():void
{
_model.sayHello();
}