Solved

Why Isn't MouseEvent.ROLL_OVER/OUT Firing Consistantly?  I Just Want to Do a Simple Toggle!

Posted on 2008-10-24
2
602 Views
Last Modified: 2013-11-11
I working on a VideoScreen component, which at this point just extends UIComponent and contains a Video object as its first child. After the Video is added to the stage, I create an overlay using a Sprite object. The overlay isn't added to the stage until the user does a MouseEvent.ROLL_OVER the VideoScreen component. The overlay is removed from the stage on MouseEvent.ROLL_OUT.

The problem here is that sometimes the MouseEvent.ROLL_OVER doesn't fire, which throws the toggle off (ROLL_OUT will add the overlay to the stage instead of removing it). Can you help me figure this out?

Here is some of my debugging output; in this case the error happens just after COUNT 2 where two 'ROLL_OUT' events are fired without a 'ROLL_OVER' between them:

----------------------------------------------------------
VideoScreen mouseRollOverOutListener COUNT: 1      (Odd numbers should always be MouseEvent type='rollOver')
[MouseEvent type="rollOver" bubbles=false cancelable=false eventPhase=2 localX=16 localY=62 stageX=16 stageY=62 relatedObject=null ctrlKey=false altKey=false shiftKey=false delta=0]
Showing overlay (expecting FALSE)...      _isShowingOverlay current value: false
Overlay should now be TRUE      _isShowingOverlay: true

VideoScreen mouseRollOverOutListener COUNT: 2      (Odd numbers should always be MouseEvent type='rollOver')
[MouseEvent type="rollOut" bubbles=false cancelable=false eventPhase=2 localX=-1 localY=-1 stageX=-1 stageY=-1 relatedObject=null ctrlKey=false altKey=false shiftKey=false delta=0]
Hiding overlay (expecting TRUE)...      _isShowingOverlay current value: true
Overlay should now be FALSE      _isShowingOverlay: false

VideoScreen mouseRollOverOutListener COUNT: 3      (Odd numbers should always be MouseEvent type='rollOver')
[MouseEvent type="rollOut" bubbles=false cancelable=false eventPhase=2 localX=-1 localY=-1 stageX=-1 stageY=-1 relatedObject=null ctrlKey=false altKey=false shiftKey=false delta=0]
Showing overlay (expecting FALSE)...      _isShowingOverlay current value: false
Overlay should now be TRUE      _isShowingOverlay: true

VideoScreen mouseRollOverOutListener COUNT: 4      (Odd numbers should always be MouseEvent type='rollOver')
[MouseEvent type="rollOver" bubbles=false cancelable=false eventPhase=2 localX=2 localY=69 stageX=2 stageY=69 relatedObject=null ctrlKey=false altKey=false shiftKey=false delta=0]
Hiding overlay (expecting TRUE)...      _isShowingOverlay current value: true
Overlay should now be FALSE      _isShowingOverlay: false

VideoScreen mouseRollOverOutListener COUNT: 5      (Odd numbers should always be MouseEvent type='rollOver')
[MouseEvent type="rollOut" bubbles=false cancelable=false eventPhase=2 localX=-1 localY=-1 stageX=-1 stageY=-1 relatedObject=null ctrlKey=false altKey=false shiftKey=false delta=0]
Showing overlay (expecting FALSE)...      _isShowingOverlay current value: false
Overlay should now be TRUE      _isShowingOverlay: true

VideoScreen mouseRollOverOutListener COUNT: 6      (Odd numbers should always be MouseEvent type='rollOver')
[MouseEvent type="rollOver" bubbles=false cancelable=false eventPhase=2 localX=8 localY=78 stageX=8 stageY=78 relatedObject=null ctrlKey=false altKey=false shiftKey=false delta=0]
Hiding overlay (expecting TRUE)...      _isShowingOverlay current value: true
Overlay should now be FALSE      _isShowingOverlay: false
----------------------------------------------------------

Here is the VideoScreen; just place it in a project sub-folder called 'controls' and use it as MXML:

<controls:VideoScreen id="videoScreen" width="300" height="225" fixDistortion="true" />





package com.futurewebstudios.controls
{
	import flash.display.Sprite;
	import flash.events.Event;
	import flash.events.MouseEvent;
	import flash.media.Video;
	import flash.net.NetStream;
	
	import mx.core.UIComponent;
	import mx.events.FlexEvent;
 
	public class VideoScreen extends UIComponent
	{
		
    //--------------------------------------------------------------------------
    //  Private properties
    //--------------------------------------------------------------------------		
		private const DEFAULT_WIDTH:Number = 320;
		private const DEFAULT_HEIGHT:Number = 240;
		private var _video:Video;
		private var _videoIsDistorted:Boolean;
		private var _overlay:Sprite;
		private var _isShowingOverlay:Boolean;
		private var _overlayShowCount:uint = 1;
		private var _stream:NetStream;
		private var _streamIsChanged:Boolean;  //changes to true once set, to false after used
		private var _maintainAspectRatio:Boolean; //needs no boolean state value; handled on property change
		
    //--------------------------------------------------------------------------
    //  Public properties
    //--------------------------------------------------------------------------
		[Bindable( event="videoIsDistortedChanged" )]
		[Inspectable( defaultValue="false" )]
		public function set fixDistortion( value:Boolean ):void
		{
			if ( _videoIsDistorted != value )
			{
				_videoIsDistorted = value;
			}
		}
		public function get fixDistortion():Boolean
		{
			return _videoIsDistorted;
		}
		
		[Bindable( event="streamChanged" )]
		[Inspectable( category="General", defaultValue="null" )]
		public function set stream( value:NetStream ):void
		{
	        if ( _stream != value )
	        {
	        	_stream = value;
	        	_streamIsChanged = true;
	         	dispatchEvent( new Event( "streamChanged" ) );   
	        }
		}
		public function get stream():NetStream
		{
			return _stream;
		}
		
		[Bindable( "maintainAspectRatioChanged" )]
		[Inspectable( defaultValue="true" )]
		public function set maintainAspectRatio( value:Boolean ):void
		{
			if ( _maintainAspectRatio != value )
			{
				_maintainAspectRatio = value;
				invalidateSize();
				invalidateDisplayList();
				dispatchEvent( new Event( "maintainAspectRatioChanged" ) );
			}
		}
		public function get maintainAspectRatio():Boolean
		{
			return _maintainAspectRatio;
		}
		
		 public function get  isShowingOverlay():Boolean
		 {
		 	return _isShowingOverlay;
		 }
	    
    //--------------------------------------------------------------------------
    //  Constructor
    //--------------------------------------------------------------------------
		public function VideoScreen()
		{
			this.addEventListener( FlexEvent.INITIALIZE, initializeListener );
			this.addEventListener( MouseEvent.ROLL_OVER, mouseRollOverOutListener );
			this.addEventListener( MouseEvent.ROLL_OUT, mouseRollOverOutListener );
			
			_video = new Video( this.DEFAULT_WIDTH, this.DEFAULT_HEIGHT );
			this.addChild( _video );
			
			super();
		}
		
    //--------------------------------------------------------------------------
    //  Public methods
    //--------------------------------------------------------------------------
	    public function attachNetStream( value:NetStream ):void
	    {
	    	_video.attachNetStream( value );
	    }
		public function showOverlay():void
		{
			if ( _isShowingOverlay == false )
			{
				trace( "Showing overlay (expecting FALSE)...\t_isShowingOverlay current value: " + _isShowingOverlay );
				_isShowingOverlay = true;
				addChild( _overlay );
				trace( "Overlay should now be TRUE\t\t\t_isShowingOverlay: " + _isShowingOverlay );
			}
			else
			{
				trace( "ERROR!!  _isShowingOverlay returns TRUE from showOverlay()" );
			}
		}
		public function hideOverlay():void
		{
			if ( _isShowingOverlay == true )
			{
				trace( "Hiding overlay (expecting TRUE)...\t\t_isShowingOverlay current value: " + _isShowingOverlay );
				_isShowingOverlay = false;
				removeChild( _overlay );
				trace( "Overlay should now be FALSE\t\t\t_isShowingOverlay: " + _isShowingOverlay );
			}
			else
			{
				trace( "ERROR!!  _isShowingOverlay returns FALSE from hideOverlay()" );
			}			
		}
	    
    //--------------------------------------------------------------------------
    //  Protected methods
    //--------------------------------------------------------------------------
		protected function setPublicValues():void
		{
			_video.width = this.width;
			_video.height = this.height;
			if ( _videoIsDistorted )
			{
				_video.smoothing = true;
			}
		}
		protected function createOverlay():void
		{
			_overlay = new Sprite();
			_overlay.graphics.beginFill( 0x000000, .5 );
			_overlay.graphics.drawRect( 0, 0,  this.width, this.height );
			_overlay.graphics.endFill();
			
			_isShowingOverlay = false;
			trace( "createOverlay() done.  Initial value should be false.  VALUE: " + _isShowingOverlay );
		}
		
    //--------------------------------------------------------------------------
    //  Private methods
    //--------------------------------------------------------------------------
		private function initializeListener( e:FlexEvent ):void
		{
			setPublicValues();
			createOverlay();
		}
		private function mouseRollOverOutListener( e:MouseEvent ):void
		{
			trace( "\nVideoScreen mouseRollOverOutListener COUNT: " + ( _overlayShowCount++ ) + "\t\t(Odd numbers should always be MouseEvent type='rollOver')\n" + e.toString() );
			( _isShowingOverlay == false ) ? showOverlay() : hideOverlay();
		}
	}
}

Open in new window

0
Comment
Question by:JaeWebb
2 Comments
 
LVL 19

Accepted Solution

by:
Gary Benade earned 500 total points
ID: 22802042
When you add the overlay as a child it effectively hijacks mouse events to the video control because it's on top of it, one way to fix this is to add the same event listeners to overlay as the video like below, another is to set overlay.mouseEnabled = false;


protected function createOverlay():void
                {
                        _overlay = new Sprite();
                        _overlay.graphics.beginFill( 0x000000, .5 );
                        _overlay.graphics.drawRect( 0, 0,  this.width, this.height );
                        _overlay.graphics.endFill();
                        
                        _isShowingOverlay = false;
                        trace( "createOverlay() done.  Initial value should be false.  VALUE: " + _isShowingOverlay );
 
                        overlay.addEventListener( MouseEvent.ROLL_OVER, mouseRollOverOutListener );
                        overlay.addEventListener( MouseEvent.ROLL_OUT, mouseRollOverOutListener );
 
                }

Open in new window

0
 

Author Comment

by:JaeWebb
ID: 22805820
If you notice the constructor, the component itself is the object listening for the events.  The video player is the first child, the overlay is the second child.  The target and current target of the MouseEvent.ROLL_OVER/OUT are always the VideoScreen component itself, never its children.  ROLL_OVER/OUT events do not bubble either.

When I follow your first suggestion and add event listeners to the overlays, the mouseRollOverOutListener is fired a bunch of times.  Just two quick swipes over the Screen produces this:

-- VideoScreen mouseRollOverOutListener --
COUNT: 89, EVENT TYPE: rollOver            (Odd numbers should always be MouseEvent type='rollOver')
Showing overlay (expecting FALSE)...      _isShowingOverlay current value: false
Overlay should now be TRUE                  _isShowingOverlay: true

-- VideoScreen mouseRollOverOutListener --
COUNT: 90, EVENT TYPE: rollOver            (Odd numbers should always be MouseEvent type='rollOver')
Hiding overlay (expecting TRUE)...            _isShowingOverlay current value: true
Overlay should now be FALSE                  _isShowingOverlay: false


When I remove the listeners at the component level and keep them on the overlays, the listener is never triggered.  When I listen for ROLL_OVER at the component level and OUT at the overlay level, I get crazy results - same thing reversed.  When I listen for ROLL_OVER on the video and ROLL_OUT on the overlay, I'm I don't get the results I expect.


When I tried your second idea and set mouseEnabled on the overlay to false, it worked as expected!  Your solution worked.   Thanks a lot.  I don't understand it since the listeners were at the container level and not at the children level, but hey - it works.

I am a bit worried about turning off the mouseEnabled property on the overlay though.  I'd like to emulate the functionality on this player:

http://www.huffingtonpost.com/2008/10/25/obama-mccain-target-the-w_n_137781.html

As you can see, when you mouseover the overlay close to the button, the button grows in response... That button must not be a child of the overlay as I originally assumed it was.  Any thoughts?  

Thanks again.


0

Featured Post

Courses: Start Training Online With Pros, Today

Brush up on the basics or master the advanced techniques required to earn essential industry certifications, with Courses. Enroll in a course and start learning today. Training topics range from Android App Dev to the Xen Virtualization Platform.

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

Suggested Solutions

This is intended to introduce all collision detection principles in flash, their strengths, weaknesses and workarounds. The main method for Collision Detection in flash is using hitTestObject. But unless you'll be pushing rectangular shapes without …
I have been doing hardcore actionscripting for some time; and needless to say I have faced a lot of problems in just understanding others' code rather than understanding what the code executes. A programmer's life can become hell when there are a lo…
The goal of the tutorial is to teach the user how to set there setting in Adobe Flash Media Live Encoder and YouTube for optimal video and audio quality.
The goal of the tutorial is to teach the user how to select which audio input to use. Once you have an audio input plugged into the laptop or computer, you will go into the audio input settings and choose which audio input you want to use.

785 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question