A well-behaved GlassPane
I have seen a lot of custom GlassPane tricks, which use GlassPane to "disable" the frame, to provide a visual effects during the lengthy tasks or to give more rich feedback during drag and drop etc...
The distinctive feature of that tricks is that GlassPane is shown only temporarily,
so when the lengthy tast or any other action is completed the custom GlassPane is made hidden and doesn't affect the frame anymore
I am going to examine special cases when you might want to show a GlassPane to provide a constant visual effects,
this way the frame is supposed to function as usual except the big translucent text e.g. "Hello Mom !" is shown on the top of the content pane :-)
So let's create a GlassPane which shows a colored rectangle at the top right corner of the frame and draws the colored circle to follow the mouse's cursor.
As a testing environment please launch this simple application
This application contains two JInternalFrames,
components on the first frame don't have any special features,
only JTextField has a popupMenu,
the second frame contains components which have a rollover effect - their background turns green when you move the mouse cursor to them, moreover each of them has a tooltip
To make it more interesting I implemented a kind of a "focus follow mouse" policy for both internal frames, so when mouse's cursor crosses frames border, the frame becomes selected
Don't close this application we will use it to test
The initial GlassPane version
Most of the similar GlassPane implementations which I tested, copied
the code from the
How to use Root Pane Swing tutorial.
The main idea is to add mouseListener and mouseMotionListener to the GlassPane, catch the mouseEvent and then redispatch it to the component found with help of SwingUtilities.getDeepestComponentAt()
Based on this solution I created the InitialGlassPane version.
Please return to the testing application and select the "GlassPane is visible" checkBox from the Options menu or simply press Alt+G to activate this menuItem.
Note: Diring the initial glassPane is visible, it is impossible to select any menuItems, use key accelerators instead
Notice the red rectangle appeared at the right top frame's corner and the red translucent circle started follow the mouse.
Let's check how it affects the frame's contents:
Click to the every component from the first internalFrame, as you can see, they seem to work:
You still can select the CheckBox and edit the JTextField
Now play with the components from the second internal frame
Here we can quickly notice some odd things like absence of rollover effects.
Here the list of problems you can see during initial GlassPane is visible:
- When Options menu is visible it doesn't react to the mouse,
the textField's popup doesn't work as well - Component's rollover effect is missed
- When you move the mouse cursor between the internal frames they don't get selected as they did before
- Tooltips become very unreliable, they might appear in unusual places or not appear at all
There is one more problem which is not so visible:
- press the JButton
- drag out of its border
- release the mouse button
- The button remains pressed !
Here is a screenshot with the mess you can get with the initial GlassPane
Now hide the glassPane by pressing Alt+G and see the difference,
everything works much better, right ?
Notice one more little feature:
- press the slider
- drag out of the *frame* border
- note that you can still move the slider's thumb
It doesn't work this way for the initial GlassPane, but after all mentioned problems this doesn't look very bad, does it ?
Why it doesn't work
GlassPane doesn't get all events you need, e.g. when you move the mouse inside it you redispatch the mouseMotion events only.
That's why rollover effect didn't work - just because components didn't receive mouseEntered/MouseExited events.
That glassPane also breaks the inner mouseEvents processing so it leads to broken drag and drop, menus and tooltips
Actually redispatching mouseEvents this way is just a bad idea
and I am going to ask to update the Swing tutorial
you can fix some problems for the current implementation but it will never work perfectly
To fix the problems our GlassPane should be absolutely transparent for mouseEvents, it means that we shouldn't add any Mouse/MouseMotion/MouseWheelListeners to it
For more information about mouseEvent transparency please refer to the my my BoF session from the latest JavaOne conference (see the MouseEvents topic)
But wait, how can I process the mouseMotion events if I didn't add any mouseListeners to the glassPane ?
To get the answer please try the
Better GlassPane
We can catch mouseEvents without mouseListeners with AWTEventListener, this way we will keep our GlassPane transparent for mouseEvents and it will not affect the mouseEvents processing
Check out the Better GlassPane implementation
Let's return to the testing application, switch the glassPane implementation to the Better GlassPane and make it visible.
After the yellow rectangle and circle appear you will not find any differences in mouse processing !
Menus, buttons, rollover everything work with no surprises
This is a really better GlassPane, but it also has a little problem
(the first GlassPane has it as well by the way):
- Hide the better GlassPane (press Alt+G)
- Move the mouse cursor inside the JTextField
- The default mouse cursor turns to "text editing" cursor
- Show the better GlassPane (press Alt+G)
- Move the mouse cursor inside the JTextField
- Look that mouse cursor doesn't change
You can see the same problem if you move the cursor to the internal frame border -
the cursor is supposed to change to show that resizing is allowed
This GlassPane prevents mouse cursor to be changed, it is always the same no matter which component you work with
Why it doesn't work
The problem is that AWT system show the cursor of the topmost visible component
and since our topmost component is GlassPane and it has the default cursor it is always the same
The fix is simple and I am happy to present the
Final GlassPane
To fix the "cursor problem" we should make our GlassPane even more transparent,
there is a special method which is used by AWT to detect the target component for the mouseEvents
public boolean contains(int x, int y)







Comments
This is awesome, but there is a bug and I'm not sure what's ...
by weiteho - 2011-09-29 14:27
This is awesome, but there is a bug and I'm not sure what's the best way to fix it.
If move the mouse over "Options" menu to the left and exit the frame, it doesn't set "point" to null, thus leaving the green cirle on the screen.
Is there a safer way to determine the mouse has exited the frame?
Locking the view.
by kzkirill - 2010-06-08 05:45
Hi. This example is very useful to me. The only thing I could not figure out is how do I block the mouse clicks if I want to my frame to to toggle into read-only mode? Thanks. Kirill.Concur, works well...but I also need a way to consume the ...
by guy_piasecki - 2012-03-01 10:17
Concur, works well...but I also need a way to consume the event in certain cases.