Flex AS3 : Find and remove elements from container of certain class - actionscript-3

How can I remove only every image found in a Bordercontainer which also holds Textinputs and Buttons ?
i tried:
for(var i:int=0;i<container.numElements;i++){
if(container.getElementAt(i) is Image){
container.removeElementAt(i);}
}
But as expected this loop does not fully work since the numElements changes which means that not all Images get removed.
I know there is some simple trick to this...but I cant think of it right now...Please help

As commenters have suggested, it seems like looping backwards would be the way to do it. I'd try something like this:
var totalElements : int = container.numElements;
for(var i:int=totalElements-1;i>=0;i--){
if(container.getElementAt(i) is Image){
container.removeElementAt(i);
}
}
By storing the numElements in a variable before starting the loop, you can be sure that the value will not change while processing the loop. Since your going backwards, you don't have to worry about the child index changing.
A second option would be to queue up the image instances in one loop and remove them in a second loop using the removeElement method. I suspect the two loop method will have significantly worse performance.

Looping backwards would be 1 way to do this.
Another would be
for(var i:int=0; i<container.numElements; i++){
if(container.getElementAt(i) is Image){
container.removeElementAt(i);
i--; //This nullifies the effect of removing an element
}
}

Related

Make all children do something...?

I'm wondering if there is an easy way to make all children simultaneously do something. In particular, I want everything on my stage to shake back and forth like an earthquake. It's a bit hard to single out everything on stage and add in the proper code because at a given time I don't always know the amount of children on stage.
Also, I'm not sure if it makes a difference, but sometimes when I addChild something, I don't go out of my way to add it to the stage...Like for a few buttons I'll do this.addChild(mybutton). I don't know if there's a way to access everything that has been addChilded even though I may not have added them directly to the stage? I'm pretty sure numChildren returns the value of the number of objects on screen, but I could be wrong...
I was thinking of doing something like
Inside my loop
if (numChildren >= 10 && nukeShakeTimer.currentCount == 0)
{
nukeShakeTimer.start();
}
if (nukeShakeTimer.currentCount > 0)
{
NukeShake();
}
NukeShake
public function NukeShake():void
{
numberChildren = numChildren;
trace(numberChildren);
while (numberChildren > 0)
{
var tempObject:Object = getChildAt(numberChildren)
if (nukeShakeTimer.currentCount % 2 == 1)
{
tempObject.x += 10;
}
if (nukeShakeTimer.currentCount % 2 == 0)
{
tempObject.x -= 10;
}
numberChildren -= 1;
}
if (nukeShakeTimer.currentCount > 30)
{
nukeShakeTimer.reset();
}
}
When I try this though, I get a runtime error for the line var tempObject:Object = getChildAt(numberChildren) and the error reads RangeError: Error #2006: The supplied index is out of bounds.
Also I feel like it may be possible to do this operation much faster without using a while loop, but maybe not. Help please, thanks!
If you want to address every child on the stage then you'll need to loop through them. As Cherniv says, changing your getChildAt call to use numberChildren-1 should resolve your error.
It shouldn't matter whether or not everything is directly on the stage or not. Looping through the stage children will get you whatever container you added the objects to. Moving that container will move its children too. (Though you'll have to do more work if you need to move those children independently).
But...
In your specific case, it looks like you just want to shake everything on the screen together, in the same direction at the same rate. In this case, I would probably just add all my objects to a single container Sprite on the stage. Then, when you want to do a shake effect, you only need to move that one container object and everything moves together.

Flash AS3 Remove Clip, reorder other items

I have a scrollpane to which I add movieclips to. I am using it a an online users list. It works well so far but now I have run into a problem. I am able to remove the movieclips I want easily enough using removechild, but when I remove it there is only a blank space where the removed clip was. So I need to know how to have the scrollpane refresh somehow and move the clips below that one removed up. How can I do this?
I have tried invalidate, refreshPane, update, etc. Maybe I didnt have them in the correct order or something, but how can this be done?
If the answer is complex, could an example be provided please? Im really not good enough with as3 just yet to code an entire algorithm to get the number of children, remove them all, readding them, etc.
Any help please?
Just a variation, but saves the -1, simply rearrange such as:
lstOnline.removeChild(lstOnline.getChildByName("NAMEHERE"));
var numleft:Number = lstOnline.numChildren;
for(var i = 0; i < numleft - 1; i++) {
lstOnline.getChildAt(i).y = i*60;
}
Guess I was a little better than I thought. In case anyone else faces this problem, the solution I found was the following:
var numleft:Number = lstOnline.numChildren;
lstOnline.removeChild(lstOnline.getChildByName("NAMEHERE"));
for(var i = 0; i < numleft - 1; i++) {
lstOnline.getChildAt(i).y = i*60;
}
lstOnline is the name of the ScrollPane and in my case 60 is the height of the added movieclips.

drawing on CandlestickSeries LineSeries makes candles narrower

I'm, using Flex 4.5.
In my application I have a CandlestickChart with basic CandlestickSeries.
I give the user the ability to add a linechart on top of the candlesChart by adding a LineSeries to the CandleStickChart as explained in adobe's docs here: here
My problem is that when the line is added it changes the shape of the candle to be narrower. Moreover, every line that is added is making the candle be narrower.
I've looked around and found this thread in adobe's forums: "CandlestickChart problem with LineSeries" which describes the exact same problem.
Unfortunately, the thread is still not answered.
Does any one knows a solution for this problem?
Thanks in advance,
Ravid
Well, the solution I found is not nice and better solutions are still appreciated but for those of you that have the same problem this solution worked for me:
The problem occurs because the candle's default item renderer uses the item's width to calculate the size of the candle which is make sense.
The problem, is that when you add another series there is a bug and the item's width is changed thefore the candle is changed.
My solution is to create a copy of the default item renderer and draw the candles based on the graph's width and number of candles you wish to put there (so you don't use the item's width).
It fixes the problem but if you use tooltips functionality than it kinda messes its placement relative to the candle.
I know this answer is a bit late, but in case it helps anyone else, here's what I did.
(It's not thoroughly tested either)
Make a class that extends the CandleStickChart class and simply override the "applySeriesSet" function as so:
override protected function applySeriesSet(seriesSet:Array /* of Series */,
transform:DataTransform):Array /* of Series */
{
// filter out the non-candlestick series
var filteredSeriesSet:Array = new Array();
for each(var series:Series in seriesSet){
if(series is CandlestickSeries) filteredSeriesSet.push(series);
}
// call the CandlestickChart applySeriesSet function with the filtered set, ignore return value
super.applySeriesSet(filteredSeriesSet, transform);
// do the code that the CartesianChart applySeriesSet function would have done, but with the unfiltered seriesSet
// would have preferred to do something like super.super.applySeriesSet(seriesSet, transform);
var n:int = seriesSet.length;
for (var i:int = 0; i < n; i++)
{
var newSeries:IChartElement = seriesSet[i];
if (newSeries is Series)
customizeSeries(Series(seriesSet[i]), i);
}
return seriesSet;
}

Generalizing instance name in ActionScript3

Imagine there is a situation : I have 100 movieclips with instance names : MC1a, MC2a, MC3a .. MC100a
and i want all of them to be invisible is there any other way than :
MC1a.visible = false; ... MC100a.visible = false;
because in this way the code gets very heavy and i thinks it's not the right way. so i was thinking is there any possible way to be something like that :
MC*a.visible = false;
all the movieclips that contains 'MC' in the begging and 'a' and the ending to disappear ? maybe something with array ?
If the parent of all these movieclips is called container you can do :
container["MC"+i+"a"].visible=false
This is due to the script nature of ActionScript.
For your particular case you can do
for(i=0;i<100;i++){
container["MC"+i+"a"].visible=false;
}
If you don't have all number between 0 and 100 you can do something like this :
for each(MovieClip mc in container){
name=mc.name;
if(name.substring(0,2)=="MC" && name.substring(-1)=="a"){
mc.visible=false;
}
}
(This is non tested pseudocode written on the fly)
There are several ways you can achieve this. First - make a Sprite container, which will be their common parent, then alter its visibility. This is not a flexible way, for example, if your movie clips are located on two different areas of stage, and need to interact somehow, you might be unable to put them all under a single parent in your display list. The second way is to make an array out of those 100 movie clips at the time of their instantiation (if possible, of course), then you iterate through the array and assign their visibility in a loop.
Basically, if you have some objects that should form a structure, consider linking them somehow first, then altering their visibility or other parameters all together. Should you need to move them all at once, or hide, the container approach will be better. Should you need them to perform similar, but not exactly same actions (say you have monsters as movie clips, and you need them to move together, but each with their own direction and speed), you should have an array.
Another thing to consider, if there is a movie clip that has a name like "MCbig_a", that is, complies with your condition, but does not exactly belong to the group of MCs you desire to make invisible, you will have to take precautions about such occurrences.
Assuming that al children are added in the same container called myContainer
var container:MovieClip = myContainer;
var i:uint = container.numChildren;
while (i--)
{
var child:* = container.getChildAt(i);
child.visible = false;
}

Masking Many Objects With 1 Mask Using `getChildAt(i).mask` Not Working

I am attempting to apply a mask to all objects on the stage except for a couple. There are a lot of different objects, and the amount of them will change in the future, so I want the masking to be done dynamically.
I wrote this code:
var i;
for (i = 0; i < this.numChildren; i++) {
if (this.getChildAt(i).name!="stage_kelp_bg" && this.getChildAt(i).name!="magnifier_mask") {
this.getChildAt(i).mask = this.magnifier_mask;
}
}
The above code is inside the document class's constructor method. Simply stating something like:
this.stage_kelp.mask = this.magnifier_mask;
works flawlessly, but only for that one object. Any idea what's wrong?
No errors are thrown, the objects just simply don't get masked.
Further research shows me that I cannot apply 1 mask to multiple objects. I have to have a mask for each object, or put all the objects into one container and mask that container.
Apparently you can use a layer to mask multiple objects on the timeline, but you can't do it programmatically without adding all the objects to one container. Unfortunately I can't do this without re-coding the entire application, so I will be using the timeline to mask things.
I would suggest you to better move all the movieclips to be masked in a single movieclip. This would be easier, if it's feasible in your case.
How about for each
for (var mc:movieClicp in this){
mc.mask=mask_}