A Flash Developer Resource Site

Page 1 of 2 12 LastLast
Results 1 to 20 of 27

Thread: [RESOLVED] How to add key listener to the stage

  1. #1
    Member
    Join Date
    Mar 2009
    Posts
    62

    resolved [RESOLVED] How to add key listener to the stage

    I want to add a key listener to my stage, but from an object 2 depths below the stage. How would I do this?

    I thought about adding the listener from my doc class, but the listener function is in the object that is two depths below the stage, which would mean I would have to pass the key values to the next movie clip, then when that one is loaded, pass it to the one with the listener function. It seems very complicated, is there an easier way which keeps with the principle of OOP?

  2. #2
    Will moderate for beer
    Join Date
    Apr 2007
    Location
    Austin, TX
    Posts
    6,801
    A keyboard event listener is one of the few times that it is acceptable to add a listener to the stage.

    Code:
    stage.addEventListener(KeyboardEvent.KEY_DOWN, someFunction);
    as long as the clip is on the display list already, that'll work.

    I don't understand your objection about the doc class. What do you mean you'd have to pass key values around?

  3. #3
    Member
    Join Date
    Mar 2009
    Posts
    62
    Quote Originally Posted by 5TonsOfFlax View Post
    A keyboard event listener is one of the few times that it is acceptable to add a listener to the stage.

    Code:
    stage.addEventListener(KeyboardEvent.KEY_DOWN, someFunction);
    as long as the clip is on the display list already, that'll work.

    I don't understand your objection about the doc class. What do you mean you'd have to pass key values around?
    See my clip is on the display list but when I add my listeners to it, I get the following error: TypeError: Error #1009: Cannot access a property or method of a null object reference. When I tarce this.stage from inside the clip, I get null.

  4. #4
    Will moderate for beer
    Join Date
    Apr 2007
    Location
    Austin, TX
    Posts
    6,801
    Then it's not on the display list. Why do you think it is?

    Is it maybe on a different frame? Stuff on a different frame isn't yet on the display list.

  5. #5
    Member
    Join Date
    Mar 2009
    Posts
    62
    Quote Originally Posted by 5TonsOfFlax View Post
    Then it's not on the display list. Why do you think it is?

    Is it maybe on a different frame? Stuff on a different frame isn't yet on the display list.
    No it should be on the display list. I traced this.parent and it displays it's parent. Also, the object is added to the stage when I export the swf, its just functionally it doesn't work.

  6. #6
    Will moderate for beer
    Join Date
    Apr 2007
    Location
    Austin, TX
    Posts
    6,801
    If that object's stage property is null, it is not on the display list. Period.

    It can have a non-null parent property. That parent may not be on the display list.

    The quickest fix is to add the key listener within a listener for ADDED_TO_STAGE, but that won't tell you what is really going wrong with the way you currently have it.

    Code:
    addEventListener(Event.ADDED_TO_STAGE, stageInit);
    
    function stageInit(e:Event):void{
      stage.addEventListener(KeyboardEvent.KEY_DOWN, someFunction);
    }

  7. #7
    Senior Member
    Join Date
    May 2004
    Posts
    226
    A keyboard event listener is one of the few times that it is acceptable to add a listener to the stage.
    Out of curiosity, can you elaborate on this? Personally I use stage listeners frequently for singleton type interactivity (i.e tooltips, text input) or for communication between separate branches of the display list.

  8. #8
    Member
    Join Date
    Mar 2009
    Posts
    62
    Quote Originally Posted by 5TonsOfFlax View Post
    If that object's stage property is null, it is not on the display list. Period.

    It can have a non-null parent property. That parent may not be on the display list.

    The quickest fix is to add the key listener within a listener for ADDED_TO_STAGE, but that won't tell you what is really going wrong with the way you currently have it.

    Code:
    addEventListener(Event.ADDED_TO_STAGE, stageInit);
    
    function stageInit(e:Event):void{
      stage.addEventListener(KeyboardEvent.KEY_DOWN, someFunction);
    }

    Thanks for your help. I'll use that ADDED to stage listener to check whats going on.

  9. #9
    Member
    Join Date
    Mar 2009
    Posts
    62
    Can you see if there is something wrong with this snippet of code, because I am doing as you say, only adding keylisteners when item added to stage but I am still getting that null error:

    addEventListener(Event.ADDED_TO_STAGE, stageInit);
    }
    function stageInit(e:Event):void{
    trace(e.target)
    addEvent()
    }

    function addEvent(){

    this.focusRect=false;
    stage.focus=this;
    this.stage.addEventListener(KeyboardEvent.KEY_DOWN ,keyUpHandler);
    this.stage.addEventListener(KeyboardEvent.KEY_UP,k eyDownHandler);
    }

  10. #10
    Will moderate for beer
    Join Date
    Apr 2007
    Location
    Austin, TX
    Posts
    6,801
    I should have added a "In my opinion" to precede that.

    I don't like to mess with the stage. It's a common resource for all swfs running in that vm. It just seems like a return to the old as2 _root or _global fallback instead of taking the time to design a structure that really reflects what you're trying to do.

    I'm genuinely curious why tooltips or textInput would need to manipulate the stage? Would a tooltip not just add a new temporary child to the item or item's parent, or a single-purpose tooltipContainer? If a textInput needs to listen for keyboard input, adding to the stage makes sense because otherwise getting those events depends on having keyboard focus.

    For event based communication between display list branches, I'd reach no higher than the document class. And even that isn't always the best way. You could create some sort of EventManager which may or may not be a singleton (doesn't need to use stage, or even be a display object), which marshalls and dispatches event signals.

    Could you give an example of some non-keyboard event that you'd want to listen for at the stage level?

  11. #11
    Member
    Join Date
    Mar 2009
    Posts
    62
    When I put comments around the code in addEvent the code all runs and the trace statement works. When its uncommented I just get TypeError: Error #1009: Cannot access a property or method of a null object reference.

  12. #12
    Will moderate for beer
    Join Date
    Apr 2007
    Location
    Austin, TX
    Posts
    6,801
    That code does look superficially correct.

    I see an unmatched close } which makes me wonder if everything is matched up right. Are you sure that's the only place you're calling addEvent?

  13. #13
    Member
    Join Date
    Mar 2009
    Posts
    62
    Yes, here is the whole thing. I only added addEvent in this one class

    Actionscript Code:
    package {
        import flash.display.*;
        import flash.events.*;
        public class Paddle extends MovieClip {
            var left:Boolean;
            var right:Boolean;
            var up:Boolean;
            var down:Boolean;
            var xPos:Number=-2;
            var yPos:Number=-2;
            function Paddle() {
                left=false;
                right=false;
                up=false;
                down=false;
                addEventListener(Event.ADDED_TO_STAGE, stageInit);         
            }
            function stageInit(e:Event):void{
                trace(e.target)
                addEvent()
            }
           
            function addEvent(){
               
                this.focusRect=false;
                stage.focus=this;
                this.stage.addEventListener(KeyboardEvent.KEY_DOWN,keyUpHandler);
                this.stage.addEventListener(KeyboardEvent.KEY_UP,keyDownHandler);
            }
           
                   
            public function keyDownHandler(e:KeyboardEvent):void {
                trace(e)
                if (e.keyCode==37) {
                    left=true;
                }
                if (e.keyCode==39) {
                    right=true;
                }
               
            }
           
            public function keyUpHandler(e:KeyboardEvent):void {
                if (e.keyCode==37) {
                    left=false;
                }
                if (e.keyCode==39) {
                    right=false;
                }
               
            }
           
            public function movePaddle() {
                if (left==true) {
                    this.x-=10;
                }
                if (right==true) {
                    this.x+=10;
                }
               
            }
               
        }
       
    }

  14. #14
    Will moderate for beer
    Join Date
    Apr 2007
    Location
    Austin, TX
    Posts
    6,801
    Other than the fact that all your vars and functions should have public or private modifiers, that code looks correct. I can't see how stage could be null in addEvent. If you trace(stage) within addEvent and comment out the rest of addEvent, you get null?

  15. #15
    Member
    Join Date
    Mar 2009
    Posts
    62
    Yes I get null. I know, it doesn't make sense.

  16. #16
    Will moderate for beer
    Join Date
    Apr 2007
    Location
    Austin, TX
    Posts
    6,801
    It's certainly not obvious what's going wrong.

    I'd add private or public modifiers and try again.

  17. #17
    Member
    Join Date
    Mar 2009
    Posts
    62
    Quote Originally Posted by 5TonsOfFlax View Post
    It's certainly not obvious what's going wrong.

    I'd add private or public modifiers and try again.
    Just done that, no avail. Maybe it's a bug, although its a pretty massive big if so.

  18. #18
    Will moderate for beer
    Join Date
    Apr 2007
    Location
    Austin, TX
    Posts
    6,801
    Using flashdevelop, I copied your code into a new project and tweaked it to compile (can't leave off the public/private in strict mode).
    Code:
    package {
        import flash.display.*;
        import flash.events.*;
        public class Paddle extends MovieClip {
            private var left:Boolean;
            private var right:Boolean;
            private var up:Boolean;
            private var down:Boolean;
            private var xPos:Number=-2;
            private var yPos:Number=-2;
    
            public function Paddle() {
                left=false;
                right=false;
                up=false;
                down=false;
                addEventListener(Event.ADDED_TO_STAGE, stageInit);      
            }
            private function stageInit(e:Event):void{
                trace(e.target)
                addEvent()
            }
            
            private function addEvent():void{
                
                this.focusRect=false;
                stage.focus=this;
                this.stage.addEventListener(KeyboardEvent.KEY_DOWN,keyUpHandler);
                this.stage.addEventListener(KeyboardEvent.KEY_UP, keyDownHandler);
    			addEventListener(Event.ENTER_FRAME, movePaddle);
            }
            
                    
            public function keyDownHandler(e:KeyboardEvent):void {
                trace(e)
                if (e.keyCode==37) {
                    left=true;
                }
                if (e.keyCode==39) {
                    right=true;
                }
                
            }
            
            public function keyUpHandler(e:KeyboardEvent):void {
                if (e.keyCode==37) {
                    left=false;
                }
                if (e.keyCode==39) {
                    right=false;
                }
                
            }
            
            public function movePaddle(e:Event = null):void {
                if (left==true) {
                    this.x-=10;
                }
                if (right==true) {
                    this.x+=10;
                }
                
            }
                
        }
        
    }
    And used it with this test document class:
    Code:
    package 
    {
    	import flash.display.Sprite;
    	import flash.events.Event;
    	
    	/**
    	 * ...
    	 */
    	public class Main extends Sprite 
    	{
    		
    		public function Main():void 
    		{
    			if (stage) init();
    			else addEventListener(Event.ADDED_TO_STAGE, init);
    		}
    		
    		private function init(e:Event = null):void 
    		{
    			removeEventListener(Event.ADDED_TO_STAGE, init);
    			// entry point
    			var p:Paddle = new Paddle();
    			p.graphics.beginFill(0);
    			p.graphics.drawCircle(0, 0, 5);
    			p.graphics.endFill();
    			addChild(p);
    		}
    		
    	}
    	
    }
    I'm not seeing your error. I do see weird behavior regarding left and right.

  19. #19
    Member
    Join Date
    Mar 2009
    Posts
    62
    Yes, I just added it directly from the document class (previously I was adding it from one displayobject down from doc class) and it traced the stage no problem. I guess it's something to do with the way I added it's parent maybe.

  20. #20
    Member
    Join Date
    Mar 2009
    Posts
    62
    You know what? I just seen in the paddle's parent function in the constructor function before I even created a new paddle, the words paddle.addEvent(). Oops, sorry for wasting your time! I cannot remember doing that at all, I was surprised to find it.

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •  




Click Here to Expand Forum to Full Width

HTML5 Development Center