I have a stage with multiple child object of different types. I have an event listener on the stage. I'd like to get the target child object on a mouse click so I can handle clicks on different object types.
Something along the lines of:
stage.addEventListener(MouseEvent.CLICK, onClick);
function onClick(e:Event):Void
{
var target = e.target
// if target type is Foo
// target.aFooMethod();
// else if target type is Bar
// target.aBarMethod();
}
Whats the correct way of doing this? Tracing e.target
seems to print the correct object type but I am unable to call any of the objects methods.
I vaguely remember in actionscript 3 being able to use target.name
but return null in this case.
It sounds like your question is mostly about runtime type identification (RTTI) and type casting. Haxe provides a number of utilities in the Type
and Reflect
classes for dealing with this.
For your code, it looks like you want specifically:
if (Std.is(target, Foo)) (cast target:Foo).aFooMethod();
else if (Std.is(target, Bar)) (cast target:Bar).aBarMethod();
Or perhaps:
if (Std.is(target, Foo)) {
var targetAsFoo:Foo = cast target;
targetAsFoo.aFooMethod();
} else if (Std.is(target, Bar)) {
var targetAsBar:Bar = cast target;
targetAsBar.aBarMethod();
}
Here is an example demonstrating a number of utilities which could help you, including Std.is
, interfaces, Type.getClass
, type casting, etc: http://try.haxe.org/#3C192
The code is as follows:
class Test {
static function main() {
function identify(tgt:Dynamic)
{
trace("1: "+tgt);
trace("2: "+Type.typeof(tgt));
trace("3: "+Type.getClassName(tgt));
trace("4: "+Type.getClass(Type.getClassName(tgt)));
trace("5: "+Std.is(tgt, Something));
if (Std.is(tgt, Something)) {
// Can cast explicitly
var casted:Something = cast tgt;
trace("Got a Something named: "+casted.name);
}
if (Std.is(tgt, Something)) {
// Can cast implicitly
var casted:Something = untyped tgt;
trace("Got a Something named: "+casted.name);
}
if (Std.is(tgt, Something)) {
// Can cast in an inline style, (obj:Type)
trace("Got a Something named: "+(tgt:Something).name);
}
if (Std.is(tgt, IHasAName)) {
// Can cast to an interface, if you prefer
var i_casted:IHasAName = (tgt:IHasAName);
trace("Got a IHasAName named: "+i_casted.name);
}
// Can reflect to see if the name field exists:
if (Reflect.hasField(tgt, "name")) {
trace("tgt has a name: "+Reflect.field(tgt, "name"));
}
if (Reflect.hasField(tgt, "length")) {
trace("tgt has a length: "+Reflect.field(tgt, "length"));
}
}
trace("----------------------------------");
trace("Calling identify with a Something:");
trace("----------------------------------");
var a = new Something("foo", 3);
identify(a);
trace("----------------------------------");
trace("Calling identify with a String:");
trace("----------------------------------");
var b = "a string";
identify(b);
trace("----------------------------------");
trace("Calling identify with anonymous:");
trace("----------------------------------");
var c = { "name" : "anonymous" };
identify(c);
}
}
class Something implements IHasAName
{
public var name:String;
public var length:Int;
public function new(name:String, length:Int)
{
this.name = name;
this.length = length;
}
}
interface IHasAName {
public var name:String;
}
The output is:
14:41:24:664 ----------------------------------
14:41:24:664 Calling identify with a Something:
14:41:24:664 ----------------------------------
14:41:24:664 1: { name : foo, length : 3 }
14:41:24:665 2: TClass({ __name__ : [Something] })
14:41:24:665 3: null
14:41:24:665 4: null
14:41:24:665 5: true
14:41:24:665 Got a Something named: foo
14:41:24:665 Got a Something named: foo
14:41:24:665 Got a Something named: foo
14:41:24:665 Got a IHasAName named: foo
14:41:24:665 tgt has a name: foo
14:41:24:665 tgt has a length: 3
14:41:24:666 ----------------------------------
14:41:24:666 Calling identify with a String:
14:41:24:666 ----------------------------------
14:41:24:666 1: a string
14:41:24:666 2: TClass({ __name__ : [String] })
14:41:24:666 3: null
14:41:24:666 4: null
14:41:24:666 5: false
14:41:24:666 tgt has a length: 8
14:41:24:667 ----------------------------------
14:41:24:667 Calling identify with anonymous:
14:41:24:667 ----------------------------------
14:41:24:667 1: { name : anonymous }
14:41:24:667 2: TObject
14:41:24:667 3: null
14:41:24:668 4: null
14:41:24:668 5: false
14:41:24:668 tgt has a name: anonymous
I vaguely remember in actionscript 3 being able to use target.name but return null in this case.
In AS3, event.target
is of type DisplayObject
, and all DisplayObjects have a .name
property, which is why you could do that in AS3.
OpenFL's Event.target
is an IEventDispatcher
, which isn't specifically associated with display classes.