Skip to content

How to use HoverManager

Mikle edited this page Aug 15, 2019 · 5 revisions

Available since: WebLaF v1.2.10 release
Required Java version: Java 6 update 30 or any later
Module: ui


What is it for?

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 AWTEventListeners and makes sure that various listeners you can register in HoverManager are informed about every change they might be interested in.


How to use it?

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.

GlobalHoverListener

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:

HoverTracker

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!

Releases

Sources

Contacts

Clone this wiki locally