Results 1 to 11 of 11
  1. #1
    zweibieren is offline Senior Member
    Join Date
    Aug 2009
    Location
    Pittsburgh, PA
    Posts
    284
    Rep Power
    6

    Default Show image on glasspane while mouse button is down

    My main window has several components, including an image thumbnail. While the user holds down the left mouse button on the thumbnail, I want the whole window to be overlaid with the full version of the image. The glass pane seems perfect. Just one problem:
    As soon as the user moves the mouse while holding it down,
    the image on the glass pane image vanishes.
    This happens because AWT invents a mouse_exited for the thumbnail on line 4103 of java.awt.Container, method trackMouseEnterExit:
    retargetMouseEvent(targetLastEntered, MouseEvent.MOUSE_EXITED, e);
    How can I get around this "feature"?
    How can I have the overlay remain visible while the mouse is down?

    Thanks, Fred Hansen
    Last edited by zweibieren; 08-31-2009 at 04:56 AM. Reason: Formatting improvement

  2. #2
    Fubarable's Avatar
    Fubarable is offline Moderator
    Join Date
    Jun 2008
    Posts
    19,316
    Blog Entries
    1
    Rep Power
    26

    Default

    Please post a small compilable program that demonstrates your problem. You can post a Jar here (with resources and source code) by changing the jar's extension to zip.

  3. #3
    zweibieren is offline Senior Member
    Join Date
    Aug 2009
    Location
    Pittsburgh, PA
    Posts
    284
    Rep Power
    6

    Arrow Test program supplied

    A test program demonstrating the problem is attached.
    It can be run with
    Java Code:
    java -jar GTest.zip

    The application displays a small window with an explanation at its top:
    Press the mouse in the image
    to enlarge it while mouse is down.
    If <i>fail</i> is checked, mouse movement
    aborts the enlarged image.

    Internally, the only difference the fail option makes is to activate the MouseExited() handler:
    Java Code:
    	public void mouseExited(MouseEvent e) {
    		if (failButton.isSelected())
    			mouseReleased(e);
    	}
    When you try the application this method gets called even when the mouse has NOT exited from anything. At most it has exited the small image. But certainly not the large overlaid image. And it is the large overlaid image that is the source of the exit.

    Fred Hansen

    With my new understanding of what is happening, I have been able to work around the problem. It would be preferable to not have the problem.
    Attached Files Attached Files
    Last edited by zweibieren; 09-03-2009 at 07:22 AM. Reason: remove some irrelevancies from the attachment

  4. #4
    zweibieren is offline Senior Member
    Join Date
    Aug 2009
    Location
    Pittsburgh, PA
    Posts
    284
    Rep Power
    6

    Default source code for the test

    The attached source code is that for the demo in my previous note.

    Some detail may help: The program has three addMouseListener() calls --
    one for the thumbnail image, one for the large overlaid image, and one for the GlassFrame.
    The glass frame is overlaid over the entire window with
    gf = new GlassFrame(getRootPane().getContentPane());
    getRootPane().setGlassPane(gf);
    The glass frame fields all mouse events and forwards them to one of the two images.
    (I would prefer not to add listeners to the images and rely on the mouse forwarding.
    But dispatchEvent only sends events to listeners that have been added,)

    At the time of the error, the mouse is down
    and the glass frame is about to receive a MOUSE_DRAGGED event.
    Before that event is sent to GTest, the method
    Container.LightweightDispatcher.trackMouseEnterExi t
    creates and dispatches an artificial MOUSE_EXITED event. See the stack trace below.

    There are two ways it might make sense to create an artificial MOUSE_EXITED:
    It might be argued that the mouse has exited the thumbnail image because it has been overlaid.
    Or perhaps the glassframe is being exited in favor of the image that now occupies its entirety.
    BUT NO. The MOUSE_EXITED is generated for the large image,
    the one component that the mouse CANNOT be exiting.
    The one component that has just been entered.


    Stack traceback

    GTest.mouseReleased:76
    GTest.mouseExited:80
    Component.processMouseEvent:6044
    JComponent.processMouseEvent:3265
    Component.processEvent:5803
    Container.processEvent:2058
    Component.dispatchEventImpl:4410
    Container.dispatchEventImpl:2116
    Component.dispatchEvent:4240
    GTest$GlassFrame.redirectMouse:166
    GTest$GlassFrame.mouseExited:145
    Component.processMouseEvent:6044
    JComponent.processMouseEvent:3265
    Component.processEvent:5803
    Container.processEvent:2058
    Component.dispatchEventImpl:4410
    Container.dispatchEventImpl:2116
    Component.dispatchEvent:4240
    Container.LightweightDispatcher.retargetMouseEvent :4322
    Container.LightweightDispatcher.trackMouseEnterExi t:4103
    Container.LightweightDispatcher.processMouseEvent: 3968
    Container.LightweightDispatcher.dispatchEvent:3916
    Container.dispatchEventImpl:2102
    Window.dispatchEventImpl:2429
    Component.dispatchEvent:4240
    EventQueue.dispatchEvent:599
    EventDispatchThread.pumpOneEventForFilters:273
    EventDispatchThread.pumpEventsForFilter:183
    EventDispatchThread.pumpEventsForHierarchy:173
    EventDispatchThread.pumpEvents:168
    EventDispatchThread.pumpEvents:160
    EventDispatchThread.run:121
    Attached Files Attached Files

  5. #5
    zweibieren is offline Senior Member
    Join Date
    Aug 2009
    Location
    Pittsburgh, PA
    Posts
    284
    Rep Power
    6

    Default

    It may be that the "source" of a MOUSE_EXITED event is not the Component that has been exited from, but rather the new Component where the mouse now resides. It seems that there is no reliable way to determine what Component is being exited from!

  6. #6
    Fubarable's Avatar
    Fubarable is offline Moderator
    Join Date
    Jun 2008
    Posts
    19,316
    Blog Entries
    1
    Rep Power
    26

    Default

    Been looking over your code, but I don't have the time yet to fully grok it. Question though, is what is it trying to accomplish with this set up? Are you trying to show the enlarged picture on click, and then get rid of it if the mouse moves away from original thumbnail rectangle boundaries? I'm betting that this problem can be simplified even more, but again, haven't yet had the time to do it. Perhaps you can? Much luck!

  7. #7
    zweibieren is offline Senior Member
    Join Date
    Aug 2009
    Location
    Pittsburgh, PA
    Posts
    284
    Rep Power
    6

    Default What the demo is trying to do

    The demo tries to show the large pic while the mouse is down, whether it moves or not.
    This works if "fail" is not checked.
    But if fail is checked, the image immediately goes away as soon as the mouse moves.

    The problem is a MOUSE_EXITED auto-generated in line 4103 of Container.
    When "fail" is not checked, the app ignores MOUSE_EXITED.
    When "fail" is checked, the app reacts to MOUSE_EXITED.
    (The value of "fail" is tested on line 79)

    Lines 175-222 can be ignored. They generate a log of mouse events if line 221 is not commented out.

  8. #8
    zweibieren is offline Senior Member
    Join Date
    Aug 2009
    Location
    Pittsburgh, PA
    Posts
    284
    Rep Power
    6

    Default

    After further coding and consideration, the problem is in my code. The GlassFrame is fielding all mouse activity and forwarding it to where it thought it should go. In the case I was objecting to, its thoughts and my expectations differed.

    I can supply a corrected GlassFrame if anyone wants it.

  9. #9
    Fubarable's Avatar
    Fubarable is offline Moderator
    Join Date
    Jun 2008
    Posts
    19,316
    Blog Entries
    1
    Rep Power
    26

  10. #10
    zweibieren is offline Senior Member
    Join Date
    Aug 2009
    Location
    Pittsburgh, PA
    Posts
    284
    Rep Power
    6

    Smile Working code for GlassFrame

    The task is to raise a full-window image for the duration of having a mouse down on a button. The button will be hidden by the window. I want a general solution so I can have various window overlays, each implemented without special consideration for being an overlay.

    The difficulty is that when a mouse is pressed subsequent events go to it instead of the overlay that has covered it.

    My first attempt was GTest_nv, a naive solution. It requires the button to forward mouse events to the overlay while the mouse is down. Works fine. But requires the button to do unnatural mouse forwarding.

    My second attempt, GTest_ok, installed a permanent glasspane that catches all mouse events and forwards them appropriately. This works fine. (It also demonstrates the spurious mouse events that started this thread.) My feeling was that this was a bit of a heavy-handed solution.

    I am finally pleased by my third attempt, GTest_better. This one treats almost all mouse events naturally. The one wrinkle is to catch mouse events from the button object where the mouse was clicked to install an overlay. The method to set an occupant into the glass pane has two arguments. First is the Component to overlay the window. Second is the event that has caused the application to make the overlay. See the call to setOccupant in this code
    Java Code:
    		
    		MouseLog mLog = new MouseLog();
    		...
    		showThumb.addMouseListener(gf.mLog.new LoggingAdapter() {
    			@Override
    			public void pressed(MouseEvent e) {
    				gf.setOccupant(showMedlar, e);
    			}
    		});

    Mouse events are logged via the MouseLog class. It offers a LoggingAdapter that works much like MouseAdapter, but also logs events. The method names are all single words (pressed, released, moved, ...). The usual MouseAdapter methods merely log the event and call the single-word-named method.

    The attachments include the three GTest versions and MouseLog. The two images will be attached to my next post.

    Here is the code of the GlassFrame object in GTest_better:
    Java Code:
        /**
         * A GlassFrame is a container for a Component overlaying the entire window.
         * Diverse Components may be swapped in and out, seriatim.
         */
        static class GlassFrame extends JPanel
                implements MouseListener, MouseMotionListener {
    		Container contentPane;      // the main contents of the window
    		Component occupant = null;  // if !=null, display occupant instead of contentPane
    		Component starter = null;  // souce from mouse event that installed occupant
    
    		MouseLog mLog = new MouseLog();  // print log of mouse events
    
    		/**
    		 * Construct a GlassFrame that will overlay the given content.
    		 * @param content The contentPane of the window
    		 */
            GlassFrame(Container content) {
                super();
    			contentPane = content;
                setOpaque(true);
            }
    
    		/**
    		 * Set or reset the Component displayed in the glass pane.
    		 * @param occ The new occupant of the glass pane.
    		 *		May be null to clear the glasspane.
    		 * @param e An event causing the change in occupancy.
    		 *  May be null. If it is a MouseEvent, the GlassFrame may
    		 *	listen to its source() for a Mouse_RELEASED event.
    		 */
    		void setOccupant(Component occ, AWTEvent e) {
    			// get rid of existing occupant
    			if (occupant != null) {
    				if (starter != null) {
    					starter.removeMouseListener(this);
    					starter.removeMouseMotionListener(this);
    				}
    				remove(occupant);
    			}
    
    			// install new occupant
    			occupant = occ;
    			if (occupant == null) {
    				setVisible(false);
    				contentPane.repaint();
    			}
    			else {
    				add(occ);
    				setVisible(true);
    				if (e instanceof MouseEvent) {
    					starter = (Component)e.getSource();
    					if (starter != null) {
    						starter.addMouseListener(this);
    						starter.addMouseMotionListener(this);
    					}
    				}
    				else starter = null;
    				occupant.repaint();
    			}
    
                revalidate();
                repaint();
    		}
    
            public void mouseClicked(MouseEvent e) { redirectMouse(e); }
            public void mousePressed(MouseEvent e) { redirectMouse(e); }
            public void mouseReleased(MouseEvent e) { redirectMouse(e); }
            public void mouseEntered(MouseEvent e) { redirectMouse(e); }
            public void mouseExited(MouseEvent e) { redirectMouse(e); }
            public void mouseDragged(MouseEvent e) { redirectMouse(e); }
            public void mouseMoved(MouseEvent e) { redirectMouse(e); }
            public void mouseWheelMoved(MouseEvent e) { redirectMouse(e); }
    
    		/**
    		 * The only mouse events are those from the starter component.
    		 * We simply redirect them to the contentpane
    		 * @param e
    		 */
    		void redirectMouse(MouseEvent e) {
    			// convert mouse to be relative to the occupant
    			Point occPt = e.getPoint();
    			occPt = SwingUtilities.convertPoint((Component) e.getSource(),
    					occPt, occupant);
    
    						// where to look for the mouse, content or glasspane
    			Component dad = contentPane, kid = null;
    
    			// set dad to lowest component at targetPoint
    			if (occPt.y >= 0)
    				while (true) {
    					if  (dad instanceof Container)
    						// for a Containers, findComponentAt descends as far as possible
    						kid = ((Container)dad).findComponentAt(occPt);
    					else
    						// for a Component, getComponentAt descends only one level
    						kid = dad.getComponentAt(occPt);
    					if (kid == null || kid == dad)
    							{ kid = dad; break; }
    					else { dad = kid; kid = null; }
    				}
    			else kid = dad;
    
    			occPt = SwingUtilities.convertPoint(starter, e.getPoint(), kid);
    			MouseEvent eNew = new MouseEvent(
    					contentPane, e.getID(), e.getWhen(), e.getModifiers(),
    					occPt.x, occPt.y, e.getXOnScreen(), e.getYOnScreen(),
    					e.getClickCount(), e.isPopupTrigger(), e.getButton());
    			mLog.event(e, "forward", eNew);
    
    			occupant.dispatchEvent(eNew);
    
    		}
    
    
    	} // end GlassFrame
    Attached Files Attached Files
    Last edited by zweibieren; 09-12-2009 at 07:31 AM. Reason: revise the comment describing GlassFrame

  11. #11
    zweibieren is offline Senior Member
    Join Date
    Aug 2009
    Location
    Pittsburgh, PA
    Posts
    284
    Rep Power
    6

    Default Images for the code

    A medlar is a fruit related to roses; its fruit is like a rose hip, only bigger. To make jelly from the fruit you first let it rot on the tree. The medlar in the picture is in the Elizabethan Herb Garden, Mellon Park, Pittsburgh, PA, USA.

    The attached images need to reside in the class directory with GTest_xx.class.

    As you will note, there are two packages:
    com.physpics.tools with MouseLog
    com.physpics.test with the other files
    Attached Thumbnails Attached Thumbnails Show image on glasspane while mouse button is down-thumb.jpg   Show image on glasspane while mouse button is down-medlar.jpg  

Similar Threads

  1. Relate JTextfield with glasspane to glasspane
    By finzaiko in forum AWT / Swing
    Replies: 1
    Last Post: 04-30-2009, 06:09 AM
  2. Mouse Event + Image Thresholding
    By ojmayolebron in forum AWT / Swing
    Replies: 0
    Last Post: 03-27-2009, 01:17 AM
  3. Image cropping in Jsf on the release of mouse
    By HarshalAuro in forum JavaServer Faces (JSF)
    Replies: 0
    Last Post: 11-12-2008, 07:24 PM
  4. Replies: 1
    Last Post: 08-25-2008, 09:48 PM
  5. Hovering mouse over a button and painting
    By gtraylo in forum AWT / Swing
    Replies: 2
    Last Post: 04-24-2008, 10:33 AM

Tags for this Thread

Posting Permissions

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