AS3: removing objects by array item reference - apache-flex

I am trying to add some Sprite objects as the contents of an array, and I would like to be able to "clear" them from the stage. I would assume that if there are loaders involved, I need to do
_imgArray[i].close();
_imgArray[i].unload();
And if I am using a sprite, I can do:
removeChild(_imgArray[i]);
None of the above work. WHY???
For an example and/or description of how I am setting this up, see Joel's post here
...but note that he hasn't included a reference for deleting them from view.
Currently I try:
for(i = 0; i < _localXML.length(); i++)
{
var tmp:BMLink = new BMLink(_localXML[i], _bw, _bh, i);
_imgArray[i] = tmp;
_imgArray[i].x = (_bw + _mainpad) * i;
_base.addChild(_imgArray[i]);
}
But this doesn't work.
I would love it if someone could explain to me why this wouldn't be proper syntax.
The class instances that are populating the array are all extending sprite, but they have their own individual loaders inside w/ progress events etc.
jml

OK; I finally figured it out through a bunch of trial and error.
It seems that I was attempting to remove the child of my main class sprite (this) rather than the sub-sprite that I had added the children to.
Sorry for the noise, but for the record, if you find that you can't do
this.removeChild(_imgArray[i]);
it's not because you don't have the correct syntax, but because you might not have an
_imgArray[i]
at that particular point of your display list hierarchy... so...
_base.removeChild(_imgArray[i]);
...worked in this case.
jml

You can make an Interface IDestroy for example with a destroy method who will manage all cleaning/removing stuff :
public interface IDestroy{
function destroy():void;
}
public class MySprite extends Sprite implements IDestroy {
..
public function destroy():void{
// remove events
..
// remove loader
..
//remove from parent
if (parent!==null){
parent.removeChild(this);
}
// etc.. more cleaning
}
}
then when you have an object who is an instance of IDestroy you can call the destroy method
if (myObject is IDestroy){
IDestroy(myObject).destroy();
}
or another way
var id:IDestroy=myObject as IDestroy;
if (id!==null)
id.destroy();
Edit:
I don't understand why any of the method i gave you in the comment will not work but _base.removeChild(_imgArray[i]) will :
addChild and removeChild accept only a DisplayObject as a parameter, so if you can do _base.addChild(_imgArray[i]) it means that _imgArray[i] inherits from DisplayObject and _imgArray[i] has a parent.
So var myDisplayObject:DisplayObject=_imgArray[i] as DisplayObject; will not return null and you will be able todo myDisplayObject.parent.removeChild(myDisplayObject); which is a general approach to your problem without relying on your _base DisplayObjectContainer (MovieClip/Sprite/...)

Related

TraversalEngine abstract class utilisation

Firstly, i am sorry but i don't speak english very well. Secondly, i have a problem with nodes which are put in a gridpane. In fact, if the focus is taken by the first one wich is located on the top left side, when i push the tab key, the focus is not taken by the other which is located on the right.
People ask me to use the traversalEngine abstract class in order to solve this problem. Nevertheless, when i try to implement an engine object, it doesn't work if i put the parameters which are shown everywhere on the web:
TraversalEngine engine = new TraversalEngine(gridPane, false) {
It ask me to remove the parameters. If i do it, i don't have access to the trav method. In fact, it is the getRoot method which appears and can be implemented :
TraversalEngine engine = new TraversalEngine() {
#Override
protected Parent getRoot() {
// TODO Auto-generated method stub
return null;
}
}
Is there something which can be make in order to solve this problem ?
Thanks you for your help
Vinz
The traversal order for focusing nodes in a parent is the order in which they occur in the child list. Assuming every child contains at most one focusable node you could simply add the children line by line or reorder the children.
This could be done programmatically of course, but adding the children in the correct order in the first place would be more efficient...
public static int getColumnIndex(Node n) {
Integer i = GridPane.getColumnIndex(n);
return i == null ? 0 : i;
}
public static int getRowIndex(Node n) {
Integer i = GridPane.getRowIndex(n);
return i == null ? 0 : i;
}
grid.getChildren().sort(Comparator.comparingInt(ContainingClass::getRowIndex).thenComparingInt(ContainingClass::getColumnIndex));

Flex and OOP customs for simple getters and setters

I am having a little play with Flex and I'm curious as to a few things.
Firstly for my instance variables I can define something like
private var _count:int = 0;
It then seems that If I have a getter and setter for count e.g
public function get count():int
{
return _count;
}
public function set count(value:int):void
{
_count = count;
}
I can from within another function call something like
count++;
which in turn sets _count to increase by one.
I.E I can seemingly access count through count or _count because I have a getter and setter..
That is correct understanding?
For something like the above is good OOP practice to have the getter and setter or simply call _count++;
Thanks
I will point out that your set count method changes the variable _points. If that is a typo, then:
Yes; that is a correct understanding. It sounds like your tests already proved that.
The private var _count will not be accessible by other classes with a reference to an instance of your class; but the public 'count' will be.
Getter and Setters are useful for performing other functionality within the class. In the context of a Flex UI Component, you may dispatch an event, or invalidate the component through one of the Flex component invalidation methods.
Separating out the get and set methods also allow you to create properties that are read only, or properties that are write only, just by leaving out the respective get or set method.
IF that is not a typo; then I have no idea why count++ would change the _count variable at all; and something else is going on with the count that you haven't shown us.

Can I control multiple instances of movieclips in a loaded swf at once?

I am loading an swf created in flash professional cs5 via the loader class into a flex 4.1 application. The flash file contains multiple movieclips that are exported for actionscript and those movieclips exist in many instances throughout the movie.
Iterating through everything, comparing class types seems to be the most easy but also the most redundant way to solve this. Is there any way of using the class name as a kind of global selector to access the clips?
I could also make the sub-clips in the flash listen for an event on which they perform an action, but I am not really sure what might be best.
In cases like these, I find that a good way to solve the problem is to create a statically accessable class that manages instances of other classes that are registered with it on instantiation. As an example...
public class GlobalStopper{
private static var clips:Array = [];
public static function add(mc:MovieClip):void{
clips.push(mc);
}
public static function stop():void{
var mc:MovieClip;
for(var i:int = 0, ilen:int = clips.length ; i < ilen ; i++){
mc = clips[i] as MovieClip;
if (mc) mc.stop();
}
}
}
and...
public class GloballyStoppableMovieClip extends MovieClip{
public function GloballyStoppableMovieClip(){
GlobalStopper.add(this);
}
}
Any and all instances of GloballyStoppableMovieClip are instantly registered with the GlobalStopper, so calling
GlobalStopper.stop();
...will stop all registered movieclips.
You can add in any other functions you want. Furthermore, instead of having add accept MovieClip instances, you could have it accept IStoppable or IPlayable objects that implement public functions stop() and play() that your movieclip subclass (or non-movieclip object that also might need to stop and play!) then implements.
But as for jQuery-like selectors? Not really the way I'd handle this particular issue.
i guess typing it out did the trick. i used the event solution:
in the root timeline i placed a function like this:
function cause():void {
dispatchEvent(new Event("do stuff",true));
}
and in the library clip's main timeline goes:
DisplayObject(root).addEventListener("do stuff", function (e:Event=null) {
... whatever ...
});
this is dirty but you get the idea.

ActionScript/Flex: Augment MouseEvents with extra information

I've got a business class, Spam and the corresponding view class, SpamView.
How can I augment MouseEvents coming out of SpamView so the MouseEvents which come out of it contain a reference to the instance of Spam which the SpamView is displaying?
Here's how I'd like to use it:
class ViewContainer {
...
for each (spam in spams) {
addChild(new SpamView(spam));
...
function handleMouseMove(event:MouseEvent) {
if (event is SpamViewMouseEvent)
trace("The mouse is being moved over spam:", spam)
}
}
Thanks!
Things I've considered which don't work:
Adding event listeners to each SpamView: the book keeping (making sure that they are added/removed properly) is a pain.
Using event.target: the event's target may be a child of the SpamView (which isn't very useful)
Listening for a MouseEvent, creating a new SpamViewMouseEvent, copying all the fields over, then dispatching that: copying all the fields manually is also a pain.
There are multiple ways to solve this puppy. I would use your #2 option, but build a utility function that gets all of the spamViews on the screen and do a couple of if-elses in looping over your spamViews.
var targ : DisplayObject = DisplayObject(event.target)
If(targ is SpamView) //then you know what's up.
If( loopedSpamView.contains(targ) ) // then the target is inside the spamViewContainer and you should be cool.
Best of luck,
Jeremy

Can i get an access to a flash player`s events pool?

I want to trace every event on every object, is there any way to do it?
Yes and no.
The one way is to simply override its dispatchEvent function:
override public function dispatchEvent(event:Event):Boolean
{
// Do something with event.
return super.dispatchEvent( event );
}
The problem, however, is that this does not always work -- sometimes dispatchEvent is not called if a child object does something. It also will not work if you are unwilling to create a special class for each instance.
Another alternative is to iterate through an array of different event types:
var evtTypes:Array = [ MouseEvent.CLICK, MouseEvent.ROLL_OVER,
MouseEvent.MOUSE_DOWN...
Event.ADDED, Event.ADDED_TO_STAGE... etc.];
for( var i:int = 0; i < evtTypes.length; i++ )
{
target.addEventListener( evtTypes[ i ], trace );
}
The problem with this method is that you'll not be able to capture custom events, only the events you have in your list. I would definitely recommend the second method for most learning and debugging problems.
I suppose a more important question, however, is "What do you want to do with these events?" Most of the documentation lists all of the events an object will dispatch: if you scroll down in the MovieClip documentation, you'll see an example.
You have to create your own registry and access it that way. So yes, there is a way to do it, but no, not easily.

Resources