ActionScript 3 Selecting a MovieClip - actionscript-3

My situation is this:
I've got several (2+) MovieClips on the stage.
Each one contains an input-textbox in addition to the background.
When I click the first MovieClip, it gets selected and a light blue shadow is displayed to indicate it like so: http://puu.sh/aueAw/3575e83aca.png
If I click the second one, it looks like this: http://puu.sh/aueEj/826e1c9cb9.png
However, when the second MovieClip's textbox is clicked, the first MovieClip becomes selected! This doesn't make any sense to me.
What could be causing this? Everything works as it should as long as I don't take these nested textboxes into account.
Thanks in advance for your helpful answers!
Best regards,
Olin K.
EDIT: Here's the code that I use to add event listeners to the MovieClips.
public function updateVisualDocument()
{
if (!uniDocument.isEmpty())
{
//Update the Visual Document if the current Document contains any pages
visualDocument.uniPage.gotoAndStop(uniDocument.getCurrentPage().getLayout());
visualDocument.uniPage.pageNumber.text = uniDocument.getPageIndex();
//Update Thumbnails
for each (var someThumb in thumbnailArray)
{
someThumb.deselect();
}
thumbnailArray[uniDocument.getPageIndex() - 1].select();
for (var i:int = 0; i < visualDocument.uniPage.panelContainer.numChildren; i++)
{
var somePanelMC = visualDocument.uniPage.panelContainer.getChildAt(i);
if (!uniDocument.getCurrentPage().hasPanels())
{
uniDocument.getCurrentPage().addPanel(somePanelMC);
}
somePanelMC.addEventListener(MouseEvent.CLICK, panelClicked);
uniDocument.getCurrentPage().getPanel(i).setPanelMC(somePanelMC);
function panelClicked(e:Event)
{
//Panel gets selected
var panelIndex:int = int(e.target.name.substring(5));
uniDocument.getCurrentPage().deselectAllPanels();
uniDocument.getCurrentPage().getPanel(panelIndex).select();
}
}
uniDocument.getCurrentPage().panelsAreFull();
uniDocument.getCurrentPage().selectFirst();
}
}
EDIT: I tried changing the textbox to the dynamic text (from the input text) type and the problem is still exactly the same. I click the textbox, it selects the first MovieClip. I think it may have to do with using the same instance name, but since it's nested, why should it matter?

Looks like I figured it out on my own. Partially. I worked off what LDMS said in his comment "did you accidentally give them the same instance name?"
Well, no, I didn't. BUT- the textboxes all had the same instance name. This is irrelevant, but it got me focused on the textboxes names, and I realized that since I had mouseChildren set to false, the textboxes were the ones firing off the event listener.
So I changed up a bit of my code to look like this:
function panelClicked(e:Event)
{
//Panel gets selected
if (!e.target.name == "myText")
{
var panelIndex:int = int(e.target.name.substring(5));
uniDocument.getCurrentPage().deselectAllPanels();
uniDocument.getCurrentPage().getPanel(panelIndex).select();
}
}
And now it works! It's a simple workaround, since doing myText.mouseEnabled = false; was not an option because it needed to be clicked.
Hope this helps someone in the future! Cheers!

Related

Get selected index of Datagrid

I want to know, how do I get the selected index, if I change the selection of a datagrid row. I´ve searched a lot and have found only the Adobe site
This is what I think is the right way:
myGrid.addEventListener(DataGridEvent.ITEM_FOCUS_IN, datagridchanged);
//DataGrid Changed Listener function
private function datagridchanged (e:DataGridEvent):void{
trace(e.selectedIndex); //Don`t know if .selectedIndex is correct
}
But nothing works, if someone could help me please?
Thanks in advance
If you simply want to know which item has been selected, you can listen to Event.CHANGE on your DataGrid.
Like this, for example:
mygrid.addEventListener(Event.CHANGE, onGridSelectedItem);
function onGridSelectedItem(e:Event):void{
var selected:int = mygrid.selectedIndex;
var item:Object = mygrid.selectedItem;
}

Can i create a function to tell a button to open a movie clip of the same name

I am new to the actionscript side of flash,
I am working on a map that has say 20 popups(movieclips) and the countries are the buttons, i have just been informed i need to add 60 more.
Below is an example of the code i have been using
english_movie.visible=french_movie.visible=turkish_movie.visible=false
english_btn.addEventListener(MouseEvent.CLICK, englishButtonClick);
french_btn.addEventListener(MouseEvent.CLICK, frenchButtonClick);
turkish_btn.addEventListener(MouseEvent.CLICK, turkishButtonClick)
function englishButtonClick(event:MouseEvent):void {
english_movie.visible=true;
english_movie.play();
french_movie.visible=turkish_movie.visible=false
}
function frenchButtonClick(event:MouseEvent):void {
french_movie.visible=true;
french_movie.play();
english_movie.visible=turkish_movie.visible=false
}
function turkishButtonClick(event:MouseEvent):void {
turkish_movie.visible=true;
turkish_movie.play();
english_movie.visible=french_movie.visible=false
}
Im thinking there must be an easier way to do this than replicating the code over and over.
Any help would be much appreciated.
Here's how to simplify the whole thing with code: Each btn object is
related to one movie object. This can be achieved with a Dictionary.
var btnToMovieAssociation:Dictionary = new Dictionary();
btnToMovieAssociation[english_btn] = english_movie; // repeat this line for every btn/movie pair
Now you have to generalise your click handler. The key difference
between each function (apart from making one certain movie visible)
is that they all make certain other movies invisible. But actually,
it's sufficient to only make the previously visible movie invisble.
To do this, create a variable that keeps track of the current visible
movie.
var currentMovie:MovieClip = english_movie;
Initialising the variable with english_movie has no effect on the
program. you can pick any other of the movies. It will make things
easier in the following code if this variable is initialised.
Now your function does effectively this:
make movie of clicked button visible
play this movie
make last movie invisible
Here's the cool part. You only add one listener. Look up if something
is in the dictionary for the clicked thing and consider that the
movie you want to show next.
addEventListener(MouseEvent.CLICK, buttonClick);
function buttonClick(event:MouseEvent):void
{
var movie:MovieClip = btnToMovieAssociation[event.target]
if (movie == null)
return; // nothing in the dictionary, it wasn't a button that was clicked.
movie.visible=true;
movie.play();
currentMovie.visible = false;
currentMovie = movie;
}
There are problems with this solution:
You still have to declare every pair, which is still tedious and prone to erro. (you have to type every name twice)
If your buttons are made up of several objects, event.target might point to them instead of the button as a whole. But with only
the btns in the dictionary and not all their individual parts,
nothing would be found in the dictionary. This can be circumvented by
setting mouseChildren = false; on every btn.
i posted this question else where and got this response
var tl:MovieClip=this;
var mc:MovieClip;
var i:int;
var buttonA:Array=[english_btn,french_btn,turkish_btn];
for(i=0;i<buttonA.length;i++){
buttonA[i].addEventListener(MouseEvent.CLICK,buttonF);
tl[buttonA[i].name.split("_")[0]+"_movie"].visible = false;
}
function buttonF(e:MouseEvent):void{
for(i=0;i<buttonA.length;i++){
tl[buttonA[i].name.split("_")[0]+"_movie"].visible = false;
}
tl[e.currentTarget.name.split("_")[0]+"_movie"].visible=true;
}
Which works great.

Blinking Caret Not Showing up in Input Text Field

I want one of my input text boxes to be the stage focus as well as have the blinking caret without the user needing to click inside the text field. I've been searching around frantically for an answer to this question, and everyone's answer boils down to this code: (the instance name of the text field being "input")
stage.focus = input;
input.setSelection(0, input.text.length);
But for some reason this code isn't working for me. Anyone have any idea why?
Update
For some reason this works:
stage.addEventListener(MouseEvent.CLICK,update);
function update(e:MouseEvent){
stage.focus = input;
}
And this does as well but the caret doesn't blink:
var counter:int=0;
stage.addEventListener(Event.ENTER_FRAME,update);
function update(e:Event){
counter++;
if(counter>30){
stage.focus = input;
}
}
This still doesn't satisfy my question though, why do you need a mouse click of some type in order to make my desired action work properly?
1.. How about if you set focus to happen inside a mouseClick function?
2.. Try this
stage.focus = input;
input.text = " "; //with a space (for blank but not empty);
input.setSelection(0, input.text.length);
3.. Bail out scenario then this utility might help or at least you'll learn something from its code Link here

Flex 4 image object returning as MovieClip object

I am working on a custom context menu in Flex4. The context menu itself works fine but I am looking for a way to tell if the ContextMenuEvent mouseTarget is an image. As it stands, the mouseTarget shows that it is a "[object MovieClip]". Which is strange because I have no movie clips in my application, only image containers. Any idea what is going on?
private function openContextMenu(e:ContextMenuEvent):void {
Alert.show(e.mouseTarget.toString());// shows [object MovieClip] when it should show [Object Image]
}
Thanks
You need to set mouseChildren on the Image to false, then the MouseEvent will refer to the Image:
if (event.target is Image) {
//do stuff
}
So after a few more hours of research I came up with the below attached to the contextMenu's item select event listener. I am sure there has to be a better way to do this, but until then...
for(var i:int = 0; i < getObjectsUnderPoint(new Point(this.mouseX, this.mouseY)).length; i++)
{
if(getObjectsUnderPoint(new Point(this.mouseX, this.mouseY))[i].parent.parent is Image)
{
//do what I need to do
}
}
Thanks NHubben for your input. It got me going down the right path of looking at children.
The component name Image has no relevance concerning what makes it up. The flex inheritance is: Image -- SWFLoader -- UIComponent -- FlexSprite -- [...] (from mx.controls.Image docs).
So what you need to do is understand what you actually have when you bring it into a AS3 environment. It seems like it gets wrapped up in a MovieClip to allow it be in the Flash's display list. It also looks like you have to go through a loader, but I'm not sure of that.
Run a test or two to find out what the object is actually made up of:
// not foolproof, and will break on some stuff,
// so you will have to fix this as needed:
private function loopDisplay(obj:Sprite):void
{
trace(obj.name + ": " + obj);
if (obj.numChildren > 0)
{
for (var i:int = 0; i < this.numChildren; i++)
{
loopDisplay(obj.getChildAt(i));
}
}
}
If you put this in a mouse down handler, then you can see what is actually there.
However, the event.target or event.currentTarget should also hold the menu item object, so you can also just loop into those objects and see what is in them.

ActionScript 3: Bullet Ricocheting

I've been having a problem with my Actionscript code. I am fairly new to Flash and AS3, so I apologize if my code seems crude or rudimentary, but I'm doing this as best as I can.
Well, in this project I'm trying to get a bullet to ricochet off a wall once. If it hits a wall again after ricocheting, the bullet will disappear.
I've created a for loop which moves the bullets, in an array. At the same time, I try to keep track of each bullet's individual number of ricochets. This works fine when I shoot a first bullet - it will ricochet and then disappear after hitting another wall. However, every bullet I fire after that disappears on the first wall it hits, before it has ricocheted. I've tried to get this to work but I just can't seem to do it.
I would be grateful if somebody could show me the problem, or suggest a change to my code.
Here is a link to my code as it is now.
Thanks, to anybody who helps.
Here are some suggestions I have:
1: Create a Bullet class that tracks its own collisions against walls. I'd also move the clearBullet() method into the bullet class itself.
public class Bullet extends Sprite
{
public var collisions:int = 0;
public var xv:Number = 0;
public var yv:Number = 0;
public function clear():void
{
if(parent)
parent.removeChild(this);
}
}
2: Update your loop to deal with this new info.
for each(var i:Bullet in bulletholder)
{
// Move bullet.
// Check for collision.
// When there is a collision, do this:
i.collisions ++;
if(i.collisions >= 2)
{
var n:int = bulletholder.indexOf(i);
bulletholder.splice(n, 1);
i.clear();
}
else
{
// Deal with changing bullet position.
}
}
I see at least a couple of problems with your code:
Your ricochetcount is clearly out of sync. i.e. you need to delete an element from that array as well.
When you delete an element from the bulletholder array (via clearBullet), you're still incrementing i, which means you end up inadvertently skipping an element.
Also I'm not sure why you need clearBullet(). You already have the index i as well as a reference to the bullet object right there in the main loop.