views:

2947

answers:

2

For some reason, the event listener I define never seems to receive any events, although I believe it should. Here's a very short description of the MXML code I'm using:

WindowedApplication
    VBox (root box)
        MenuBar
        TabNavigator
            VBox (first tab)
                Canvas
            VBox (second tab)

If I add a listener for KEY_DOWN events to WindowedApplication or the root VBox, the handler receives the events just fine. But if I add the listener to the Canvas or the first tab VBox, the handler never seems to receive any. (I assume here that just clicking on the Canvas area gives it focus - am I correct?)

I'm just starting out with Flex, so I'm hoping I made a silly beginner's mistake somewhere. I'd be very grateful for any help. Thanks!

+2  A: 

you are wanting to know and catch a keydown event dispatched from the canvas? I would say that yes, you are probably having trouble with the canvas actually having focus. This link may help some:

http://livedocs.adobe.com/flex/3/html/help.html?content=Capturing_User_Input_3.html

Knowing what it is you are trying to achieve would help to give you a better solution. Why is it that you are wanting to catch keyboard events only on the canvas?

Ryan Guill
+2  A: 

Agree with Ryan, and I'd add that I've sometimes found it helpful, when handling keyboard events in general, to wire up my listeners to the event's capture phase, rather than the target or bubbling phases (note the third argument, false by default):

stage.addEventListener(KeyboardEvent.KEY_DOWN, handleKeyDown, true);

Thinking for instance of a casual game in which the arrow keys control the core action somehow (Tetris, maybe -- rotate left, rotate right), responding to an event during the capture phase means can have distinct advantages. From the docs:

In the capturing phase, Flex examines an event's ancestors in the display list to see which ones are registered as a listener for the event. Flex starts with the root ancestor and continues down the display list to the direct ancestor of the target. In most cases, the root ancestors are the Stage, then the SystemManager, and then the Application object.

So in this case, you can be sure the stage's listener will get the notification first, before anyone else, and can respond accordingly -- either by terminating the event-propagation entirely (sometimes you might want to do that) or by translating it into a more application-specific, custom event:

private function handleKeyDown(event:KeyboardEvent):void
{
    if (event.keyCode == Keyboard.LEFT)
    {
     dispatchEvent(new Event("rotateLeft"));
    }
    else if (event.keyCode == Keyboard.RIGHT)
    {
     dispatchEvent(new Event("rotateRight"));
    }
    else
    {
     event.stopPropagation();
    }
}

... and keeping you from peppering keyboard listeners all over your app.

Event-propagation phases are described in more detail here. Check it out as well -- there's great info in there that's well worth knowing.

Christian Nunciato
I had the same issue with my keyDown event not being called. I had added the event to the canvas and not the STAGE. When you are new to Flash/Flex this is easy to miss.This answer helped a lot, thanks.
Chris Masterton