AS3 TypedDictionary? - actionscript-3

public dynamic class TypedDictionary extends Dictionary {
private var _type:Class;
public function TypedDictionary(type:Class, weakKeys:Boolean = false) {
_type = type;
super(weakKeys);
}
public function addValue(key:Object, value:_type):void {
this[key] = value;
}
public function getValue(key:Object):_type{
return this[key];
}
...
I want to make TypedDictionary with typisation. But I can not use _type in addValue and getValue. The idea is to use next construction :
var td:TypedDictionary = new TypedDictionary(myClass, true);
td.addValue("first", new myClass());
...
var item:myClass = td.getValue("first");
item.someFunction();
Is any ability to use dynamic class type?

If I un derstand what you are asking for.
This is untested code so it could be error prone, but it should get you on the right path.
public dynamic class TypedDictionary extends Dictionary {
private var _type:Class;
public function TypedDictionary(type:String, weakKeys:Boolean = false) {
_type = getDefinitionByName(type) as Class;
super(weakKeys);
}
public function addValue(key:Object, value:*):void {
if(_type == getDefinitionByName(getQualifiedClassName(value))){
this[key] = value;
}else{
trace('failed type match')
}
}
public function getValue(key:Object):*{
return this[key];
}
...
var td:TypedDictionary = new TypedDictionary("com.somepackage.myClass", true);
td.addValue("first", new myClass());
var item:myClass = td.getValue("first");
item.someFunction();

Related

Flex - Problems in accessing static variable on another mxml page

First.mxml - Contains a Datefield control as follows:
<mx:DateField id="G2_CRTLoadDate" width="150" selectedDate="{modelProxy.G2_CRTLoadDate}" change="{modelProxy.G2_CRTLoadDate = event.currentTarget.selectedDate;changeManagerStatus()}"/>
I'm assigning this Datefield value to a static variable CERT_LOAD_DATE as follows(First.mxml):
[Bindable]
public static var CERT_LOAD_DATE:String = "";
private function changeManagerStatus():void
{
CERT_LOAD_DATE = G2_CRTLoadDate.selectedDate.toDateString();
}
Second.mxml -Here, I have a Combobox as follows:
<mx:ComboBox id="General_Release_Dates"
selectedItem="{modelProxy.General_Release_Dates}"
valueCommit="{model.General_Release_Dates = event.currentTarget.selectedItem;updateReleaseDate(event)}"
change="{model.General_Release_Dates = event.currentTarget.selectedItem;updateReleaseDate(event)}" close="closeHandler(event);" includeInLayout="true" visible="true">
</mx:ComboBox>
Inside the closeHandler function, I'm trying to access the variable CERT_LOAD_DATE as follows:
private function closeHandler(evt:DropdownEvent):void {
var CurrentDate:Date = new Date();
if(General_Release_Dates.selectedLabel.toString() == "TBD")
{
Alert.show(First.CERT_LOAD_DATE);
}
}
The alert box displays no value (null). Please help.
I can't figure out the relationship between First.mxml and Second.mxml from your question.
However, the following code can't access First.mxml.
Alert.show(First.CERT_LOAD_DATE);
Because the "First" is not the same instance as loaded "First.mxml".
How about to use singleton? It's accessible from anywhere.
1st, add MySingleton.as class like this.
package foo.bar
{
public class MySingleton
{
private var _cert_load_date:String;
public function MySingleton(internally:SingletonInternal)
{
super();
if(internally == null)
{
throw new Error("Please use getInstance() method.");
}
}
public static function getInstance():MySingleton
{
return SingletonInternal.instance;
}
public function set cert_load_date(value:String):void
{
_cert_load_date = value;
}
public function get cert_load_date():String
{
return _cert_load_date;
}
}
}
import foo.bar.MySingleton;
class SingletonInternal{
public static var instance:MySingleton
= new MySingleton(new SingletonInternal());
public function SingletonInternal(){}
}
How to use
Set value at First.mxml.
public var singleton: MySingleton = MySingleton.getInstance();
private function changeManagerStatus():void
{
singleton.cert_load_date = G2_CRTLoadDate.selectedDate.toDateString();
}
Second.mxml
public var singleton: MySingleton = MySingleton.getInstance();
private function closeHandler(evt:DropdownEvent):void {
var CurrentDate:Date = new Date();
if(General_Release_Dates.selectedLabel.toString() == "TBD")
{
Alert.show(singleton.cert_load_date);
}
}
Updated: Aug 27 10:00(JST)
I think there are two way to change First.mxml's element using singleton.
1) Binding the DateField value to singleton variables, and clear the value at Secend.mxml.
2) Assign to singleton variables whole "First", and control from Second.mxml.
I'll write here the 2nd way.
If you use this way, anything is controlable from Second.mxml.
MySingleton.as
private var _first:Object;
public function set first(value:Object):void
{
_first = value;
}
public function get first():Object
{
return _first;
}
First.mxml
singleton.first = this;
Second.mxml
public function something(): void{
First(singleton.first).G2_CRTLoadDate.selectedDate = null;
// The cast is unnecessary. Following code also works.
// singleton.first.G2_CRTLoadDate.selectedDate = null;
}
Also you can execute First.mxml's public function from Second.mxml.
singleton.first.someFunctionDefinedAtFirst();

as3 use setter in other class(parent)

I'm trying to make a simple setter which i like to access with a child class.
Here is the parent class code :
public class DeGeheimeMissie extends MovieClip
{
var deLader:URLLoader;
var deXmlData:XML;
public var hoofdVragenLijst:Object = new Object();
public var subVragenLijst:Object = new Object();
public var hetAntwoord:String;
public function DeGeheimeMissie()
{
var hetVerzoek:URLRequest;
hetVerzoek = new URLRequest("dialogen.xml");
deLader = new URLLoader(hetVerzoek);
deLader.addEventListener(Event.COMPLETE, vragenGeladen);
deLader.load(hetVerzoek);
instObama.addEventListener(MouseEvent.CLICK, showVragen);
instObama.buttonMode = true;
instObama.useHandCursor = true;
}
public function set hetAntw(str:String):void
{
hetAntwoord = str;
}
and here is the child class where i try to access it:
public class Rutte extends MovieClip
{
var deLader:URLLoader;
var deXmlData:XML;
public var antwoordenOverzicht = [];
//constructor
public function Rutte()
{
var hetVerzoek:URLRequest;
hetVerzoek = new URLRequest("dialogen.xml");
deLader = new URLLoader(hetVerzoek);
deLader.addEventListener(Event.COMPLETE, antwoordenGeladen);
deLader.load(hetVerzoek);
instRutte.addEventListener(MouseEvent.CLICK, showAntwoorden);
instRutte.buttonMode = true;
instRutte.useHandCursor = true;
}
public function setAntwoord(e:MouseEvent)
{
var antw = e.currentTarget.text.charAt(0);
trace(e.currentTarget.text.charAt(0));
this.parent.hetAntw(antw);
}
The error i get here is:
1061: Call to a possibly undefined method hetAntwoord through a reference with static type flash.display:DisplayObjectContainer.
You should try this, this is how we use setters :
this.parent.hetAntw = antw;
But why making a public setter on a public static var ?

Constructor argument error

my english is poor because this is not my main language but i'll do my best.
I need help with the argument to the constructor because i dont know where to take all these information.
here my defaultitem class:
public class DefaultItem extends MovieClip
{
private var _id:String;
private var _lastX:int;
private var _lastY:int;
private var _isStackable:Boolean = false;
private var _type:String;
private var _isDragging:Boolean = false;
private var _currentContainer:DefaultContainer;
private var _lastContainer:DefaultContainer;
public function DefaultItem($id:String, $type:String, $x:int, $y:int)
{
stop();
id = $id;
type = $type;
x = $x;
y = $y;
addEventListener(Event.ADDED_TO_STAGE, onAddedToStage);
}
private function onAddedToStage(e:Event):void
{
removeEventListener(Event.ADDED_TO_STAGE, onAddedToStage);
init();
}
public function init():void
{
buttonMode = true;
mouseChildren = false;
_lastX = x;
_lastY = y;
addEventListener(MouseEvent.MOUSE_UP, onMouseUpHandler);
addEventListener(MouseEvent.MOUSE_DOWN, onMouseDownHandler);
this.stage.addEventListener(MouseEvent.MOUSE_UP, onMouseUpHandler);
//resolve drag bugs
}
/**
* Mouse Event Handlers
*/
private function onMouseDownHandler(e:MouseEvent):void
{
isDragging = true;
this.mouseEnabled = false;
dispatchEvent(new ItemEvent(ItemEvent.ITEM_PICKED_UP, this));
}
private function onMouseUpHandler(e:MouseEvent):void
{
// check if item is being dragged
if (isDragging)
{
isDragging = false;
this.mouseEnabled = true;
dispatchEvent(new ItemEvent(ItemEvent.ITEM_DROPPED, this));
}
}
/**
* Getters & Setters
*/
public function get id():String { return _id; }
public function set id(value:String):void
{
_id = value;
}
public function get lastX():int { return _lastX; }
public function set lastX(value:int):void
{
_lastX = value;
}
public function get lastY():int { return _lastY; }
public function set lastY(value:int):void
{
_lastY = value;
}
public function get currentContainer():DefaultContainer { return _currentContainer; }
public function set currentContainer(value:DefaultContainer):void
{
_currentContainer = value;
}
public function get lastContainer():DefaultContainer { return _lastContainer; }
public function set lastContainer(value:DefaultContainer):void
{
_lastContainer = value;
}
public function get type():String
{
return _type;
}
public function set type(value:String):void
{
_type = value;
}
public function get isDragging():Boolean
{
return _isDragging;
}
public function set isDragging(value:Boolean):void
{
_isDragging = value;
}
/**
* Destroys item
*/
public function destroy():void
{
buttonMode = false;
removeEventListener(MouseEvent.MOUSE_UP, onMouseUpHandler);
removeEventListener(MouseEvent.MOUSE_DOWN, onMouseDownHandler);
this.stage.removeEventListener(MouseEvent.MOUSE_UP, onMouseUpHandler);
}
}
}
here my item class:
public class Slot extends DefaultContainer
{
// vars
private var _id:String;
private var _item:DefaultItem;
private var _type:DefaultItem;
//private var isdragging:DefaultItem;
public var defaultitem:DefaultItem = new DefaultItem(id, _type, x, y);
// trace(DefaultItem.getisDragging());
//trace(DefaultItem.getisDragging());
/**
* Constructor
*
* #param $id Slot id
*/
public function Slot($id:String)
{
addEventListener(MouseEvent.ROLL_OUT, onMouseOutHandler);
addEventListener(MouseEvent.ROLL_OVER, onMouseOverHandler);
id = $id;
setLabel($id);
stop();
}
/**
* Slot Methods
*/
public function getItem():DefaultItem { return _item; }
public override function addItem($item:DefaultItem):void
{
_item = $item;
addChild(_item);
//
this.gotoAndStop(2); //active slot
}
public override function removeItem($item:DefaultItem):void
{
removeChild(_item);
_item = null;
this.gotoAndStop(1); //default slot
}
public function hasItem():Boolean
{
if (_item == null)
{
return false;
}
else
{
return true;
}
}
private function onMouseOutHandler(e:MouseEvent):void {
trace("mouseOutHandler");
this.gotoAndPlay("out");
}
private function onMouseOverHandler(e:MouseEvent):void {
trace("mouseoverHandler");
// if (!isDragging)
//{
//trace("drag = "+ isDragging);
this.gotoAndPlay("over");
// }
//else {
//trace("drag = " + isDragging );
//this.gotoAndPlay("dragUp");
// }
}
/**
* Getters & Setters
*/
public function get id():String { return _id; }
public function set id(value:String):void
{
_id = value;
}
public function setLabel($label:String):void
{
this.label.text = $label;
}
/**
* Destroy
*/
public function destroy():void
{
removeItem(_item)
}
}
}
the problem is here public var defaultitem:DefaultItem = new DefaultItem(id, _type, x, y);
i'm not sure id and _type is working good. I wanna know where to get all these information because i need to call the function isdragging and if i use the var id he target the item and not the defaultcountainer id thanks guys
You are creating and instance of DefaultItem but passing wrong arguments.
public var defaultitem:DefaultItem = new DefaultItem(id, _type, x, y);
Since this is created prior to constructor running, id is null, _type is not a String and is null and x, y are out of scope.
It should be:
public var defaultitem:DefaultItem;
Then in Slot constructor:
id = $id;
defaultitem = new DefaultItem(id, _type, x, y);
//but _type is still not a String and is still null
It seems to me like you're dragging an item onto something, sorry if I've misunderstood.
But, in that case, you can use something like:
var itemID:String = e.target.id;
var itemType:String = e.target._type;
That's in case you have the item's id and type stored somewhere.
Also, as for the x and y, those depend on where you want to put them.
For example, if you had a character and you wanted to give him a sword, it would look something like:
//somewhere in your code:
weapon.id = "Iron Sword";
weapon._type = "Sword";
//And then when you get to the default item part...
var itemId:String = e.target.id;
var itemType:String = e.target._type;
var defaultitem:DefaultItem = new DefaultItem(itemID,itemType, character.x, character.y);
Again, sorry if I misunderstood. Best of luck with your program!

Isn't this how to specify a passing information custom event?

This game is a board game so it need to pass information but mostly not dynamically.
Is this the correct definition of a Custom Event?
package
{
import flash.events.Event;
public class Set extends Event
{
public var addsub:Boolean;
public var kanaex:String;
public var valueex:uint;
public var xx:uint;
public var yy:uint;
public static const BOARD_SET_CHANGED:String = "BoardSetChanged";
public static const BOX_SET_CHANGED:String = "BoxSetChanged";
public function Set(type:String, addsub1:Boolean, kanaex1:String, valueex1:uint, xx1:uint,yy1:uint, bubbles:Boolean = false, cancelable:Boolean = false)
{
super(type, bubbles, cancelable);
addsub = addsub1;
kanaex = kanaex1;
valueex= valueex1;
xx = xx1;
yy = yy1;
}
override public function clone():Event
{
return new Set(type, addsub, kanaex,valueex,xx,yy, bubbles, cancelable );
}
override public function toString():String
{
return formatToString("BoardSetChanged","addsub","kanaex","valueex","xx","yy","bubbles", "cancelable");
}
}
}
If so why does this code leave the
event attributes undefined?
import Set;
import flash.events.*;
this.addEventListener(Set.BOARD_SET_CHANGED, Exclusion);
private function Exclusion(e:Event)
{
var a:Boolean = e.addsub;
var b:uint = e.xx;
var c:uint = e.yy;
if (a == true)
{exclusionx.push(b);
exclusiony.push(c);
}
else if (a == false)
{exclusionx.pop();
exclusiony.pop();
}
}
Try to change the parameter of Exclusion to Set
private function Exclusion(e:Set):void {
}

Flex - Cursor search in ArrayCollection not working

So I'm following the book Adobe Flex 4 Training From the Source by Michael Labriola, Jeff Tapper and Matthew Boles, for context.
I'm building a Shopping Cart Class that recieves a ShoppingCartItem object (which is just a POAO) from the mxml and adds it to an ArrayCollection via this public function:
private var $items:ArrayCollection = new ArrayCollection();
public function addItem(item:ShoppingCartItem):void
{
var inCart:Boolean = false;
var currentItem:ShoppingCartItem;
for(var i:int = 0; i < $items.length; i++)
{
currentItem = $items.getItemAt(i) as ShoppingCartItem;
if(item.$product == currentItem.$product)
{
inCart = true;
break;
}
}
if(inCart)
{
currentItem.$quantity++;
}
else
{
$items.addItem(item);
}
updateTotal();
$items.refresh();
}
According to the book, the same function can be achieved with an IViewCursor, like this.
public function addItem(item:ShoppingCartItem):void
{
var cursor:IViewCursor = $items.createCursor();
var inCart:Boolean = cursor.findFirst(item);
if(inCart)
{
var existing:ShoppingCartItem = cursor.current as ShoppingCartItem;
existing.$quantity++;
}
else
{
$items.addItem(item)
}
}
Problem is, when I use this function the item quantity is never updated. Then I have a Shopping cart with 2 entries of 1 product when I should have 1 entry of 2 products. Tracing the inCart boolean yields "false", no matter what I do. The first function works properly and as expected, so I have no idea why the data is not being updated correctly. Also, if I call $items.refresh(); at the end of the second function (for sorting), it throws a NullPointerException error.
Another thing to notice is that I'm using a book for Flex 4 when I'm using the 4.6.0. SDK, the last Adobe release before it was gifted to Apache. I don't know if this is of any importance.
Here's the code for ShoppingCartItem:
[Bindable]
public class ShoppingCartItem
{
public var $product:Product;
public var $quantity:uint;
public var $subtotal:Number;
public function getSubTotal():Number
{
calculateSubTotal();
return $subtotal;
}
public function toString():String
{
return "[ShoppingCartItem]"+$product.prodName+":"+$quantity;
}
public function calculateSubTotal():void
{
this.$subtotal = $product.listPrice*$quantity;
}
public function squeak():void
{
trace("squeak");
}
public function ShoppingCartItem(product:Product, quantity:uint = 1)
{
this.$product = product;
this.$quantity = quantity;
calculateSubTotal();
}
EDIT: More information request by Sunil D.
Product.as class:
[Bindable]
public class Product
{
public var catID:Number;
public var prodName:String;
public var unitID:Number;
public var cost:Number;
public var listPrice:Number;
public var description:String;
public var isOrganic:Boolean;
public var isLowFat:Boolean;
public var imageName:String;
public function toString():String
{
return "[Product]"+this.prodName;
}
public static function buildProductFromAttributes(data:XML):Product
{
var p:Product;
var isOrganic:Boolean = (data.#isOrganic == "Yes");
var isLowFat:Boolean = (data.#isLowFat == "Yes");
p = new Product(data.#catID,
data.#prodName,
data.#unitID,
data.#cost,
data.#listPrice,
data.#description,
isOrganic,
isLowFat,
data.#imageName);
return p;
}
public static function buildProduct(o:Object):Product
{
var p:Product;
p = new Product(o.catId,o.prodName,o.unitID,o.cost,o.listPrice,
o.description,(o.isOrganic == 'true'),
(o.isLowFat == 'true'),o.imageName);
return p;
}
public function Product(cid:Number, name:String, uid:Number, cost:Number, listp:Number, desc:String, iso:Boolean, ilf:Boolean, imn:String)
{
this.catID = cid;
this.prodName = name;
this.unitID = uid;
this.cost = cost;
this.listPrice = listp;
this.description = desc;
this.isOrganic = iso;
this.isLowFat = ilf;
this.imageName = imn;
}
}
ArrayCollection sorting sortfield is the Product POAO contained in the ShoppingCartItem Class. It's done within the constructor function of ShoppingCart like this:
public class ShoppingCart
{
[Bindable]
private var $items:ArrayCollection = new ArrayCollection();
public function ShoppingCart()
{
var prodSort:Sort = new Sort();
var sortField:SortField = new SortField("product");
prodSort.fields =[sortField];
$items.sort = prodSort;
$items.refresh();
}
The reason the viewcursor approach is not working is because the item (ShoppingCartItem) is not in the $items collection. This method compares object references and will hence not find your item if it is another instance of ShoppingCartItem.
In the first approach you are not comparing object references of ShoppingCartItem, but comparing the "product" property of the items.