Results 1 to 11 of 11
- 08-31-2009, 03:46 AM #1
Senior Member
- Join Date
- Aug 2009
- Location
- Pittsburgh, PA
- Posts
- 282
- Rep Power
- 4
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,This happens because AWT invents a mouse_exited for the thumbnail on line 4103 of java.awt.Container, method trackMouseEnterExit:
the image on the glass pane image vanishes.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 HansenLast edited by zweibieren; 08-31-2009 at 03:56 AM. Reason: Formatting improvement
-
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.
- 09-03-2009, 05:36 AM #3
Senior Member
- Join Date
- Aug 2009
- Location
- Pittsburgh, PA
- Posts
- 282
- Rep Power
- 4
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:
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.Java Code:public void mouseExited(MouseEvent e) { if (failButton.isSelected()) mouseReleased(e); }
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.Last edited by zweibieren; 09-03-2009 at 06:22 AM. Reason: remove some irrelevancies from the attachment
- 09-03-2009, 11:16 AM #4
Senior Member
- Join Date
- Aug 2009
- Location
- Pittsburgh, PA
- Posts
- 282
- Rep Power
- 4
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());The glass frame fields all mouse events and forwards them to one of the two images.
getRootPane().setGlassPane(gf);
(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
- 09-04-2009, 05:47 AM #5
Senior Member
- Join Date
- Aug 2009
- Location
- Pittsburgh, PA
- Posts
- 282
- Rep Power
- 4
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!
-
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!
- 09-04-2009, 07:00 AM #7
Senior Member
- Join Date
- Aug 2009
- Location
- Pittsburgh, PA
- Posts
- 282
- Rep Power
- 4
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.
- 09-09-2009, 11:14 PM #8
Senior Member
- Join Date
- Aug 2009
- Location
- Pittsburgh, PA
- Posts
- 282
- Rep Power
- 4
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.
-
Indeed, let's see it! Oh, and congrats!
- 09-12-2009, 06:21 AM #10
Senior Member
- Join Date
- Aug 2009
- Location
- Pittsburgh, PA
- Posts
- 282
- Rep Power
- 4
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 GlassFrameLast edited by zweibieren; 09-12-2009 at 06:31 AM. Reason: revise the comment describing GlassFrame
- 09-12-2009, 06:29 AM #11
Senior Member
- Join Date
- Aug 2009
- Location
- Pittsburgh, PA
- Posts
- 282
- Rep Power
- 4
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
Similar Threads
-
Relate JTextfield with glasspane to glasspane
By finzaiko in forum AWT / SwingReplies: 1Last Post: 04-30-2009, 05:09 AM -
Mouse Event + Image Thresholding
By ojmayolebron in forum AWT / SwingReplies: 0Last Post: 03-27-2009, 12:17 AM -
Image cropping in Jsf on the release of mouse
By HarshalAuro in forum JavaServer Faces (JSF)Replies: 0Last Post: 11-12-2008, 06:24 PM -
How to show pixel Coordinate and RGB value when mouse is tracking over an image
By Mazharul in forum Java 2DReplies: 1Last Post: 08-25-2008, 08:48 PM -
Hovering mouse over a button and painting
By gtraylo in forum AWT / SwingReplies: 2Last Post: 04-24-2008, 09:33 AM


LinkBack URL
About LinkBacks
Reply With Quote

Bookmarks