-
Notifications
You must be signed in to change notification settings - Fork 235
How to use HoverManager
Available since: WebLaF v1.2.10 release
Required Java version: Java 6 update 30 or any later
Module: ui
One of the things lacking in Swing is ability to globally track various component states. One of such states is hover
- it is a simple state informing that user has mouse cursor hovering over the component that has the state.
There are various solutions to how hover
state can be implemented for Swing components - most popular is simply registering MouseListener
on the component and tracking mouse enter and exit events. But there are multiple issues with that approach - hover state won't be properly removed in some cases because you simply won't receive "exit" event until mouse is moved. Also it can be completely skipped when component is hidden or removed. It is also not sufficient to track hover
state application-wide.
To solve these and some other problems I've created HoverManager
that continuously tracks hovered component through multiple registered AWTEventListener
s and makes sure that various listeners you can register in HoverManager
are informed about every change they might be interested in.
The only way to use HoverManager
is to register one of the available listeners, so first you need to decide what exactly you want to listen for - all hover change events or only hover change events for particular component.
All listeners receive events from the same source, but they are filtered and delivered differently.
Can be registered to listen to all hover change events:
HoverManager.registerGlobalHoverListener ( new GlobalHoverListener ()
{
@Override
public void hoverChanged ( @Nullable final Component oldHover, @Nullable final Component newHover )
{
...
}
} );
It can also be registered using an existing component:
HoverManager.registerGlobalHoverListener ( component, new GlobalHoverListener ()
{
@Override
public void hoverChanged ( @Nullable final Component oldHover, @Nullable final Component newHover )
{
...
}
} );
That method is particularly useful if you have a component that will be listening to provided events. Events will not be limited to that component, but listener will be registered in HoverManager
differently to help prevent possible memory leaks through the listener itself.
I recommend using second option or registering HoverTracker
for particular component as described below.
Here is a small practical example:
public final class GlobalHoverListenerExample
{
public static void main ( final String[] args )
{
SwingUtilities.invokeLater ( new Runnable ()
{
@Override
public void run ()
{
WebLookAndFeel.install ();
final WebLabel label = new WebLabel ( "...", WebLabel.CENTER );
final WebColorChooserPanel panel = new WebColorChooserPanel ();
TestFrame.show ( 10, false, 10, label, panel );
HoverManager.registerGlobalHoverListener ( label, new GlobalHoverListener ()
{
@Override
public void hoverChanged ( @Nullable final Component oldHover, @Nullable final Component newHover )
{
final String prev = oldHover != null ? ReflectUtils.getClassName ( oldHover ) : "none";
final String next = newHover != null ? ReflectUtils.getClassName ( newHover ) : "none";
label.setText ( prev + " -> " + next );
}
} );
}
} );
}
}
It will display a small frame with color chooser and label showing what component is currently under the cursor:
Can be registered to listen to particular component hover change events:
HoverManager.addHoverTracker ( component, new DefaultHoverTracker ( component, false )
{
@Override
public void hoverChanged ( final boolean hover )
{
...
}
} );
Here is a small practical example:
public final class HoverTrackerExample
{
public static void main ( final String[] args )
{
SwingUtilities.invokeLater ( new Runnable ()
{
@Override
public void run ()
{
WebLookAndFeel.install ();
final WebLabel label = new WebLabel ( "Panel not hovered", WebLabel.CENTER );
final WebCheckBox directHoverOnly = new WebCheckBox ( "Direct hover only", false );
directHoverOnly.setHorizontalAlignment ( WebCheckBox.CENTER );
final WebButton button = new WebButton ( "Sample button" );
final WebPanel panel = new WebPanel ( StyleId.panelDecorated, new BorderLayout (), button );
panel.setBackground ( Color.WHITE );
panel.setPadding ( 20 );
TestFrame.show ( 20, false, 20, label, directHoverOnly, panel );
final DefaultHoverTracker hoverTracker = new DefaultHoverTracker ( panel, false )
{
@Override
public void hoverChanged ( final boolean hover )
{
label.setText ( hover ? "Panel hovered" : "Panel not hovered" );
}
};
HoverManager.addHoverTracker ( panel, hoverTracker );
directHoverOnly.addActionListener ( new ActionListener ()
{
@Override
public void actionPerformed ( final ActionEvent e )
{
hoverTracker.setDirectHoverOnly ( directHoverOnly.isSelected () );
}
} );
}
} );
}
}
It will display a small frame with label showing whether or not panel is currently hovered:
You can also enable or disable directHoverOnly
setting of the DefaultHoverTracker
that switches tracking mode.
That's all you need to know to start using this feature.
I will update HoverManager
with more options in the future, so stay tuned!
If you found any mistakes or inconsistency in this article, feel that it is lacking explanation or simply want to request an additional wiki article covering some topic:
I will do my best to answer and provide assistance as soon as possible!