AS3 Flash change combobox value cause keydown events are disabled - actionscript-3

I'm using Flash Pro CS6.
I created a fla project and put in a ComboBox.
Then i place following code in action:
import flash.events.KeyboardEvent;
this.stage.addEventListener(KeyboardEvent.KEY_DOWN, onKeyDown);
this.stage.addEventListener(KeyboardEvent.KEY_UP, onKeyUp);
function onKeyDown(e:KeyboardEvent)
{
trace("Keydown :" + e.charCode);
}
function onKeyUp(e:KeyboardEvent)
{
trace("Keyup :" + e.charCode);
}
both event work fine at the beginning but when i change the ComboBox value, the event KEY_DOWN no longer work.
here is my sample project:
Untitled-1.fla

As Baris said, you should use stage.focus = null after selecting combobox element :
cb.addEventListener(Event.CHANGE, cb_on_change)
function cb_on_change(e:Event):void {
stage.focus = null
}
Click anywhere on the stage dont solve problem if there is no element on the stage that will receive the focus.

When you click on the combobox it gets focus which prevents keyboard events from firing on the stage.
Do they start working again if you click anywhere on the stage. Alternatively you can clear the focus with stage.focus = null.

Related

Why doesn't stage.addEventListener(KeyboardEvent.KEY_DOWN, onKeyDown, true) work?

I want to listen to stage for keyboard event, and I want to catch an event directly when it appears (not in bubbling or target). Why can't I do this?
Actually it seems that I can't use useCapture for keyboard events at all.
I want to open my inner console window by pressing tilda button, and change focus to input field. So, I wrote something like this
public function init(stage:Stage):void
{
stage.addEventListener(KeyboardEvent.KEY_DOWN, onStageKeyDown);
}
private function onStageKeyDown(event:KeyboardEvent):void
{
event.stopImmediatePropagation();
switch(event.keyCode)
{
case Keyboard.BACKQUOTE:
visible = !visible;
stage.focus = visible ? inputField : stage;
break;
}
}
The problem is, it writes "`" character in my input, which I don't want it to do. So, I decided to try to listen to keyboard event in capture phase to stop its propagation. But it seems that stage can't have capture phase, because there is no nodes before it. How can I handle that situation properly?
To simply answer your question, you can listen for keyboard events on the capture phase.
Most likely, the reason you can't, is because nothing has focus. If nothing has focus in your application then the stage will not get a keyboard event. By default, when a swf runs nothing has focus.
Give an item focus when your application starts (anything besides the stage itself), and the event will come.
public function init(stage:Stage):void
{
stage.focus = this; //assuming this is the document class
stage.addEventListener(KeyboardEvent.KEY_DOWN, onStageKeyDown, true);
}
Now, to follow up with what you are actually trying to accomplish (aside from your actual question) all you need to do is listen for the right event (TEXT_INPUT). Your answer is close, but it can be much simpler without the need for flags or a key down listener:
stage.focus = this; //give something focus, probably not needed if you have to click the text input in order to input text
//listen on the capture phase for text input
stage.addEventListener(TextEvent.TEXT_INPUT, onStageTextInput, true);
function onStageTextInput(event:TextEvent):void
{
switch(event.text)
{
//if the new text was a backquote or # sign, don't let the event trigger it's normal action
case "`":
case "#":
event.preventDefault(); //prevent default is needed
break;
}
}
I finally found a workaround for this problem.
First of all: handling and stopping KeyboardEvent.KEY_DOWN is NOT preventing TextField from getting input. That's sad because in this case it would be useful, but it seems there is some other reasons for not doing this.
So, what I should do is listen for TextEvent.TEXT_INPUT by inputField
inputField.addEventListener(TextEvent.TEXT_INPUT, onTextInput);
and listen to KeyboardEvent.KEY_DOWN by stage
stage.addEventListener(KeyboardEvent.KEY_DOWN, onStageKeyDown);
in case I may still want to put tilda of backquote signs in my TextField (for example by coping and pasting them) I decided to use a flag
private function onStageKeyDown(event:KeyboardEvent):void
{
switch(event.keyCode)
{
case Keyboard.BACKQUOTE:
...
inAction = true;
break;
}
}
so when TextEvent.TEXT_INPUTevent fires I can see if that was opening window action or not. And if it is, then preventDefault() behaviour, which means NOT inputting received sign in TextField
private function onTextInput(event:TextEvent):void
{
if(inAction)
{
event.preventDefault();
inAction = false;
}
}

My mouse clicks created and triggered my eventListener at the same time

I tried to achieve the following but failed with the code below:
Click mouse once to appear the box.
Click it again to disappear the box.
What happened is that when I fire the mouse.click event (by clicking), that triggered the "stage.addEventListener(MouseEvent.CLICK, boxGone)" event listener as well. At the screen there is nothing happened because I technically addChild and removeChild the box at the same frame.
I am guessing my initial click created and triggered the event listener at the same time.Is there anyway to avoid this from happening without changing my triggering event(mouse click)? below is the code:
public function ClassConstructor(){
addEventListener(MouseEvent.CLICK, onMouseClickHandler);
}
private function onMouseClickHandler(e:MouseEvent):void{
box.x = stage.mouseX;
box.y = stage.mouseY;
box.gotoAndPlay(1);
stage.addChild(box);
stage.addEventListener(MouseEvent.CLICK, boxGone);
}
private function boxGone(e:MouseEvent):void{
stage.removeChild(box);
stage.removeEventListener(MouseEvent.CLICK, boxGone);
}
Thanks in advance,
Sunny
Modify your first listener with:
stage.addEventListener(MouseEvent.CLICK, onMouseClickHandler);
The event goes from your main class to the stage, and you add the second listener in between, so it is called just after the function's closure. Another solution, to be sure, would be to call
e.stopImmediatePropagation();
This prevents any listener to catch the same event.

AS3 - Button inside MovieClip triggers MC's event

On stage, I have a MovieClip named "mc" with a simple rectangle drawn inside. mc also has a Button child named "btn" which is another simple rectangle ( smaller than mc's rectangle obviously). Then I have this code on stage.
function mcDown( _e:MouseEvent):void{
trace( "mc" );
}
function btnClick( _e:MouseEvent):void{
trace( "btn" );
}
mc.addEventListener( MouseEvent.MOUSE_DOWN, mcDown );
mc.btn.addEventListener( MouseEvent.CLICK, btnClick );
The problem I am having is when click the button, mcDown event is also triggered and traces both "mc" and "btn".
How can I make it so that when I click the button, it triggers only btnClick and not mcDown along? I tried MOUSE_UP instead of CLICK, same problem. And mcDown event has to remain MOUSE_DOWN.
There is no way to prevent bubbling except setting the bubbles parameter as false in the dispatchEvent.
dispatchEvent(EVENT_TYPE, BUBBLES,....);
However, you can avoid the bubbling by doing a check. Just have the below line as first line of your listener function it avoids the events dispatched from all objects other then targets.
if(e.eventPhase != EventPhase.AT_TARGET) return;
So, for your sample code, when you click on the button both the events dispatches but in the mcDown function it won't execute after the above said line.
If you add button in a MC, and you click on the button, you also click on the MC, because the part of the MC that is under the button is still there and it runes the function for the whole of the MC, you can't remove it.
So it's good idea to make a function that will check if the button is pressed, otherwise it will run the function for the whole of the MC.
This one should do it.
//add this in you constructor
mc.addEventListener(MouseEvent.MOUSE_DOWN, myReleaseFunc);
function myReleaseFunc(e:MouseEvent):void {
if(e.currentTarget.name == Btn1) //Btn1 is instance name for a button
{
Btn_func1();
}
else if(e.currentTarget.name == Btn2) //Btn2 is another button.
{
Btn_func2();
//For every button you'll need to add another function and if statement to check if that button was clicked.
}
else
{
Mc_func();
}
}
// this outside the main class
function Mc_func():void{
//you code here
}
function Btn_func1():void{
//you code here
}
function Btn_func2():void{
//you code here
}
I think that this way is much more effiecient and it will works better and faster and you'll have a lot smaller chance of overloading the system.

Catch enter press in flash block on webpage

I have a webpage with a flash header. In the flash header (block), different dropdownmenus are present together with a 'submit' button.
When the user presses 'enter', i want to submit the form.
However, I can't seem to be able to catch any key :
stage.addEventListener(KeyboardEvent.KEY_DOWN, onKeyDownFunc);
root.addEventListener(KeyboardEvent.KEY_DOWN, onKeyDownFunc);
optiesPanelNew.addEventListener(KeyboardEvent.KEY_DOWN, onKeyDownFunc);
optiesPanelNew.ddOptiesMerk.addEventListener(KeyboardEvent.KEY_DOWN, onKeyDownFunc);
function onKeyDownFunc(evt)
{
if (evt.keyCode == Keyboard.ENTER)
{
submitForm();
}
}
This javascript works if the html part of the page (non flash) has focus :
document.body.onkeydown = function theFunction()
{
alert("keydown");
}
Edit: Oh no, the flash file was written in AS2 ... sorry :-/
FYI : the code I ended up using was : (AS2) :
var keyListener:Object = new Object();
keyListener.onKeyDown = function():Void
{
if(Key.getCode()==13)
submitForm();
}
Key.addListener(keyListener);
I think you need to specify the event's type in the handler (i.e. KeyboardEvent) because this way the dispatched object will be cast to a Event object when its instance is passed to the handler. The Event class doesn't have the keyCode property, and subsequently the condition to submit the form is not met. That's why the form doesn't get submitted.
So, try replacing the
function onKeyDownFunc(evt)
line, with
function onKeyDownFunc(evt:KeyboardEvent)
and it should do the trick.
Have a great day.

Is it possible to remove an eventListener temporarily (i.e. until a function has been executed)

I am doing actionscript 3 at the moment and was wondering if it was possible to remove and eventListner temporarily. I know of removeEventListener, however, that removes the eventListener completely and i cannot click the button again.
If you want some more details, here the exact problem. I have function that when a button is pressed, an object appears. In the function which makes this object there is an eventListener which leads to a function which allows the user to press that object. When you press that object it disappear and the button will animate. However, since the original eventListener still exists, you can press the object while in motion and create a new object. So to the point: What i want to do is disable the eventListener while the button is moving, and reactivate it when it stops.
The best way is to simply use a flag which tells the function if the animation is complete or not. Here's an example of what I'm talking about using TweenLite as tween library:
public class CreateButton extends Sprite{
private var animating:Boolean = false;
public function CreateButton(){
this.addEventListener(MouseEvent.CLICK, onClick, false, 0, true);
}
private function onClick(event:MouseEvent):void{
if(this.animating == false){
// Trigger creation functionality
TweenLite.to(this, 0.5, {/* Parameters for the actual animation */ onComplete:animationComplete});
this.animating = true;
}
}
private function animationComplete():void{
this.animating = false;
}
}
It is best practice to remove the listener if it's functionality is to be disabled. You could however set the .mouseEnabled to false if you want to disable it's click functionality without removing the listener.