I'm setting a custom ITickProvider on a NumericAxis:
var yaxis = new NumericAxis();
yaxis.TickProvider = new MyTickProvider();
At runtime the ITickProvider.Init method is never called:
public class MyTickProvider : ITickProvider
{
public void Init(IAxis axis)
{
// never called
}
public double[] GetMajorTicks(IAxisParams axis)
{
// this method is called first
return new double[] {};
}
public double[] GetMinorTicks(IAxisParams axis)
{
// this method is called second
return new double[] { };
}
}
What do I need to do so that Init is called? I'm using version 3.1.0.5013 of SciChart.
This issue has been fixed in a recent release (v3.1.0.5067).
Related
Shouldn't this (or something like it) work? and/or How can I accomplish this some other way?
class A {
void init() {initializeSomething()}
}
main() {
var f = A.init;
A a = new A();
a.f();
}
I want, in general, to store a reference to an instance method
somewhere, then call it somewhere else (something I can do in most other
languages, including JavaScript). I thought functions were first class
in Dart... and aren't methods functions? Are methods not first class?
It works as long as the method is static (which is of no use in my case) but not for instance methods...
Functions and methdods are different. You can only call methods on an instance of a class that has this method.
In your example (var f = A.init) you reference an instance method like a static (class) method.
What works is:
make init static
class A {
static void init() => initializeSomething();
// or
// static void init() {
// initializeSomething();
// }
}
main() {
var f = A.init;
A a = new A();
a.f();
}
or use a reference to init() of an actual instance of A:
class A {
void init() => initializeSomething();
}
main() {
A a = new A();
var f = a.init;
a.f();
}
Here's a toy example distilled from a complex class:
public class MyClass {
public function MyClass() {
trace('Created');
}
public static function makeObjectAsync(callback:Function):void {
inner();
function inner():void {
var object:MyClass = new MyClass(); // line 10
callback(object);
}
}
}
After calling the static function:
MyClass.makeObjectAsync(function(object:Myclass):void { ... })
the following run-time exception occurs at line 10:
TypeError: Error #1007: Instantiation attempted on a non-constructor.
Why is this, and what can I do about it?
Edit
It appears that new (MyClass)() works. Now I'm possibly more confused.
Not too clear on the WHY to be honnest. It has to do with the scope inherited by anonymous functions, depending on how they are declared.
I have 2 solutions for you though.
If your makeObject method was not static, it would work.
Declare your anonymous function the other way :
public static function makeObjectAsync(callback:Function):void {
var inner : Function = function():void {
var object:MyClass = new MyClass();
callback(object);
};
inner();
}
You shouldn't call your variable "object". Why do you nested your inner function? Why don't you just:
public static function makeObjectAsync(callback:Function):void {
callback(new MyClass());
}
Or if you really want that nested function:
public static function makeObjectAsync(callback:Function):void {
inner();
function inner():void {
callback(new MyClass());
}
}
And you can't recall the class' constructor again, use a function which is called in the constructor then call it again. With this you aren't referencing the constructor but creating a new instance of the class.
This one is driving me crazy for a couple hours. I try to call a method kill(); (in function takeDamage()) which is in the same class, yet it won't find it.
package classes.ship
{
imports ...
public class Ship extends MovieClip
{
var speed:Number;
var shootLimiter:Number;
public static var health:Number;
public static var maxHealth:Number;
public function initialize()
{
var stageReff:Stage = this.stage as Stage;
stage.addEventListener(KeyboardEvent.KEY_DOWN, reportKeyDown);
stage.addEventListener(KeyboardEvent.KEY_UP, reportKeyUp);
stage.addEventListener("enterFrame", move);
}
//code
public static function takeDamage(d):void
{
health -= d;
if(health <= 0)
{
health = 0;
kill();
}
Main.healthMeter.bar.scaleX = health/maxHealth;
}
public function kill():void
{
var boom = new Explosion();
stage.addChild(boom);
boom.x = this.x;
boom.y = this.y;
this.visible = false;
//Main.gameOver();
}
//code
}
}
Has it to do with var stageReff:Stage = this.stage as Stage; ?
Thanks in advance.
kill() is an instance method, but takeDamage is a static class method. You can't call instance methods from a static class method. You can only call instance methods when you have an instance reference to call it on.
nice simple one for early in the year!
You have declared the function 'takeDamage' as a static method - this means that it does not belong to a particular instance of the class Ship, instead it belongs to the Class itself. Static methods and properties can be a bit confusing if you are new to OOP, but are easily explained through a quick example:
Class Member Property
In this example we declare a new Class definition for a Ship where we can define the speed of the ship instance via setSpeed().
public class Ship {
private var speed : Number;
public function setSpeed(value : Number) : void {
this.speed = value;
}
public function getSpeed() : Number {
return this.speed;
}
}
Now we will create a couple of ships and set their speed:
var scoutShip : Ship = new Ship();
scoutShip.setSpeed(500); // Scout's are fast!
var cargoShip : Ship = new Ship();
cargoShip.setSpeed(10); // Cargo ships are sloooow.
trace("Scout Ship Speed: " + scoutShip.getSpeed()); // 500
trace("Cargo Ship Speed: " + cargoShip.getSpeed()); // 10
As you can see from the above, each new instance of Ship that we create can have its own Speed - this is a fundamental of Object Orientated Programming (where the Ship is the Object and it's speed is the data).
Static Property
Now we will create another class, this time called StaticShip which uses a static property instead, note the use of the static keyword:
public class StaticShip {
private static var speed : Number;
public function setSpeed(value : Number) : void {
this.speed = value;
}
public function getSpeed() : Number {
return this.speed;
}
}
Because the speed property is static it is shared across all instances of StaticShip; for example:
var scoutShip : StaticShip = new StaticShip();
scoutShip.setSpeed(500); // So the scout should move at 500
var cargoShip : StaticShip = new StaticShip();
cargoShip.setSpeed(10); // ... and the Cargo move at 10, as before
trace("Scout Ship Speed: " + scoutShip.getSpeed()); // 10
trace("Cargo Ship Speed: " + cargoShip.getSpeed()); // 10
Notice how both StaticShips move at 10 - this is because we set the Speed of the 'cargoShip' instance last - as the 'speed' property in StaticShip is declared static it is shared across all instances of that Class.
Now, just as you can have static properties in Classes, you can also have static functions. Usually, when you call a Class' method (ie: setSpeed()) you need to invoke that method on an instance (ie: scoutShip.setSpeed(500);), however, Static Methods allow you to interact with other static members of a given class, here's another example:
Static Method Example
public class StaticMethodShip {
private static var speed : Number;
// Note that setSpeed is now declared as static
public static function setSpeed(value : Number) : void {
this.speed = value;
}
public function getSpeed() : Number {
return this.speed;
}
}
Now, we can still create new instances of StaticMethodShip as before, but because we have now declared 'setSpeed' as static, we can't invoke setSpeed on an instance:
var scoutShip : StaticMethodShip = new StaticMethodShip();
// This call will trigger Error #1180 - Call to a possibly undefined Method because
// setSpeed was declared as static.
scoutShip.setSpeed(500);
Instead, we can now only invoke the setSpeed() method on the StaticMethodShip Class, ie:
// Set the speed of all StaticMethodShip instances.
StaticMethodShip.setSpeed(250); // all StaticMethodShips travel at 250.
// Proof!
var shipOne : StaticMethodShip = new StaticMethodShip();
var shipTwo : StaticMethodShip = new StaticMethodShip();
trace("ShipOne Speed: " + shipOne.getSpeed()); // 250
trace("ShipTwo Speed: " + shipTwo.getSpeed()); // 250
Static methods are useful when you want to define behaviour for all instances of a given Class (ie: all StaticMethodShips move at the specified speed, all fade out Tweens last for 0.25 seconds, etc); but they are also used in common design Patterns such as the Static Factory Method
Now, to the reason you are seeing your error - member level methods are able to invoke static methods, ie:
public class StaticExampleOne {
public static function getName() : String {
return "Robbe";
}
public function traceName() : void {
// traces 'Robbe'.
trace(getName());
}
}
In usage (new StaticExampleOne().traceName()) this works just fine - member methods can access static methods without problem, however this doesn't work the other way around:
public class StaticExampleTwo {
private var name : String = "Robbe";
public function getName() : void {
return this.name;
}
public static function traceName() : void {
// Throws Error #1180.
trace(getName());
}
}
This is because static methods have no scope (ie: They do not know which instance of the Class they are referring too because they can only reference other static members) and therefore can not access class level members (methods and properties).
To solve your problem you could introduce a new static property to Ship called 'STAGE' (typically static properties are written in ALL CAPS to differentiate them from member properties) and then make your kill() method static.
Hope this helps and good luck!
Jonny.
If an AS3 method returns a reference to a complex type, is there any way to make that 'readonly', like how you can have const member functions in C++? An architecture I want to use calls for a class building itself from a passed template object... and really the template object should not be modifiable. I'm currently forced to add call-back enumerators and/or lots of extra accessor methods.
Flex has an ObjectUtil.clone() method that will make a deep copy. The copy will still by modifiable, but since it's a copy, the changes won't propagate back to the original.
The method is no complicated so if you're not using Flex, just add this to a util class:
public static function copy(value:Object):Object
{
var buffer:ByteArray = new ByteArray();
buffer.writeObject(value);
buffer.position = 0;
var result:Object = buffer.readObject();
return result;
}
There is no way to do that in AS3, there is Sam's way of doing it, but it still requires copying that object before you return it, depending on the complexity of that object, it can impact the performance.
Immutable interfaces are a near-equivillant to const-correctness. Here's an example:
interface CPoint {
function get x():Number;
function get y():Number;
}
class Point implements CPoint {
private var _x:Number;
private var _y:Number;
public function get x():Number { return _x; }
public function get y():Number { return _y; }
public function set x(val:Number) { _x = val; }
public function set y(val:Number) { _y = val; }
public function normalize():void {
var length:Number = Math.sqrt(_x*_x + _y*_y);
_x /= length;
_y /= length;
}
public function Point(x:Number, y:Number) {
_x = x; _y = y;
}
}
If you return a Point as a CPoint reference, then its fields cannot be altered. You can do an explicit cast to a Point from a CPoint to force access, but you can do the same thing with const casting in C++.
Unfortunately, AS3 doesn't support covariance like it should, so things get unnecessarily difficult for const sub-objects. For example, if you had a Line class that was made up of two points, you might want to say line.start.x = 47; if you have full access to the line, but allow reading of line.start.x through an immutable interface. You could do this if there was covariance, but instead you'll need to add separate get properties for mutable and immutable properties. So, you'd end up instead with line.cstart.x for reads from a CLine. Something like this:
interface CLine {
function get cstart():CPoint;
function get cend():CPoint;
}
class Line implements CLine {
private var _end:Point;
private var _start:Point;
public function get cend():CPoint { return _end; }
public function get cstart():CPoint { return _start; }
public function get end():Point { return _end; }
public function get start():Point { return _start; }
public function Line(x1:Number, y1:Number, x2:Number, y2:Number) {
_start = new Point(x1, y1);
_end = new Point(x2, y2);
}
}
I would create a flash.utils.proxy object. You could create a proxy object that has read only implementation of a child that is passed in.
Here is the documentation for creating a proxy object. http://livedocs.adobe.com/flash/9.0/ActionScriptLangRefV3/flash/utils/Proxy.html
Note: Proxy is pretty damn slow, since you'll be bypassing native object checking, and replacing it with a function call -- which when using a lot will be slow. I would do some simple performance testing first.
note: This is pseudo-code.
use namespace flash_proxy;
dynamic class ReadOnly extends flash.utils.Proxy {
private var target:Object;
public function ReadOnly(target:Object) {
this.target = target;
}
flash_proxy function getProperty(name:*):*
return target[name];
}
flash_proxy function setProperty(name:*, value:*):void
// throw an error or do nothing
}
}
You could then do:
var readOnly:ReadOnly = new ReadOnly(stage.loaderInfo.parameters);
readOnly.someparameter = 'newvalue';
trace(readOnly.someparameter); // should be old value
I have a class which extends the Sprite object in as3. I need to be able to override the transform.matrix setter in this class but haven't been successful in doing so.
I've tried many things, along with creating my own separate class which extends the Transform class and then overrides its set matrix function, and set my transform = new CustomTransform(). Sadly this didn't work.
In code this is what i tried:
public class MyClass extends Sprite
{
public function MyClass()
{
super(); transform = new MyTransform(this);
}
}
class MyTransform extends Transform
{
public function MyTransform(dp:DisplayObject)
{
super();
}
override public function set matrix(value:Matrix)
{
super.matrix = value;
customcode();
}
}
All help is greatly appreciated!
This seems to work:
public class MyClass extends Sprite
{
public function MyClass()
{
super();
transform = new MyTransform(this,super.transform);
// i'm drawing a rect just to see the results of scaling
graphics.beginFill(0xff0000);
graphics.drawRect(0,0,100,100);
graphics.endFill();
}
override public function get transform():Transform {
var tmp:Transform;
if(super.transform is MyTransform) {
tmp = super.transform;
} else {
tmp = new MyTransform(this,super.transform);
}
return tmp;
}
override public function set transform(value:Transform):void {
var tmp:Transform;
if(value is MyTransform) {
tmp = value;
} else {
tmp = new MyTransform(this,value);
}
super.transform = tmp;
}
}
public class MyTransform extends Transform
{
public function MyTransform(dp:DisplayObject,transf:Transform = null)
{
super(dp);
if(transf) {
for(var prop:String in transf) {
this[prop] = transf[prop];
}
}
}
override public function set matrix(value:Matrix):void
{
super.matrix = value;
// customcode();
}
}
Use:
var sp:MyClass = new MyClass();
var mat:Matrix = sp.transform.matrix;
mat.scale(3,3);
trace(sp.transform);
sp.transform.matrix = mat;
addChild(sp);
The problem is that, even if you create and assign your tranform to be of type MyTransform, the getter returns a regular Transform object. There's something weird about how transform objects work in Flash (this is also true for SoundTransform, for instance). There's some kind of cache mechanism implemented in a rather lame way that forces you to reassign the instance if you want to commit your changes.
I mean this pattern:
var t:Transform = mc.transform;
// do something with t
mc.transform = t;
So I think this is related to why your code doesn't work as expected.
To get around this, I'm checking both in the setter and the getter if the trasnform object passed is of type MyTransform. If it is, I use it as is. If it's not, I create a MyTransform object and copy all of the properties from the original Transform. It'd be nice if the Transform class had a clone method, but it doesn't, so I implemented this simple copy mechanism. Not sure if this doesn't mess up with some internal state in Transform (could be the case). I haven't tested it apart from applying a scale, once. You might want to do it, as there could be other side effects I'm not considering. Also, this is probably not the most performant. But I can't think of another way to have your matrix setter called.
Edit
Using a static/global dispatcher is not a good idea except you really need it to be global. Implementing IEventDispatcher, since you can't directly extend EventDispatcher, is what you want.
The code needed for that is a bit verbose, but it's a no-brainer anyway. All you need is having an internal instance of event dispatcher and implement the methods of the interface. In said methods, you forward the parameteres to the actual dispatcher.
public class MyTransform extends Transform implements IEventDispatcher
{
private var _dispatcher:EventDispatcher;
public function MyTransform(dp:DisplayObject,transf:Transform = null)
{
super(dp);
_dispatcher = new EventDispatcher(this);
if(transf) {
for(var prop:String in transf) {
this[prop] = transf[prop];
}
}
}
override public function set matrix(value:Matrix):void
{
super.matrix = value;
// customcode();
}
public function dispatchEvent(event:Event):Boolean {
return _dispatcher.dispatchEvent(event);
}
public function addEventListener(type:String,listener:Function,useCapture:Boolean = false, priority:int = 0, useWeakReference:Boolean = false):void {
_dispatcher.addEventListener(type,listener,useCapture,priority,useWeakReference);
}
public function removeEventListener(type:String,listener:Function,useCapture:Boolean = false):void {
_dispatcher.removeEventListener(type,listener,useCapture);
}
public function hasEventListener(type:String):Boolean {
return _dispatcher.hasEventListener(type);
}
public function willTrigger(type:String):Boolean {
return _dispatcher.willTrigger(type);
}
}