0

I want to make a Java program with Swing layout where there is a menu on the left that is expanded when a mouse hovers over the menu area, but auto contracts after your mouse leaves.

I am trying to imitate the effect of something like mobile Youtube for Android, or Weebly's editor. Fro those who don't know, both layouts have menus on the left that expand when your mouse hovers over them. Then after your mouse leaves the area, the menu contracts again and is out of view.

I was able to create the JSplitPane containing my menu successfully, but I have no idea how to make it automatically expand when the user's mouse hovers over the JSplitPane component, or how to make it contract after the mouse leaves the area.

In case anyone is wondering why: This type of menu is easy for the user to use but because it hides away when unneeded, allows me to have more space for the main part of the program.

Any help would be appreciated thanks!

mKorbel
  • 109,525
  • 20
  • 134
  • 319
XQEWR
  • 638
  • 3
  • 11
  • 24
  • A little off topic, but you might be interested in having a look at [Sliding-Layout](https://github.com/AurelienRibon/sliding-layout) – MadProgrammer Nov 27 '13 at 19:17
  • @MadProgrammer Looks interesting, will look into, from what the example shows it's something similar to what I want Thanks! – XQEWR Nov 27 '13 at 19:19
  • `Fro those who don't know, both layouts have menus on the left that expand when your mouse hovers over them.` == hmmm for example I don't know, you have to search for accordion, some of them are react to mouse events – mKorbel Nov 27 '13 at 19:21

2 Answers2

2

Well make use of jSplitPan.setDividerLocation(location);: Sets the location of the divider. location - an int specifying a UI-specific value (typically a pixel count).

jSplitPane1.addMouseMotionListener(new MouseMotionAdapter() {
            public void mouseMoved(MouseEvent evt) {
                // use evt.getSource() if needed
                jSplitPan1.setDividerLocation(location);
            }
        });

You will probably need to compute the divider location a little bit intelligently. hints: by computing the relevant preferred-size hints. The part relevant should be discovered by you.

Take a look into official tutorial page to know: How to use MouseMotionListeners including other event listeners.

Sage
  • 15,290
  • 3
  • 33
  • 38
  • Yeah I think I understand that part, but what I'm looking for is how to make it move just by having the mouse hover over the JSplitPane. Maybe some short of MouseListener? But I don't exactly know – XQEWR Nov 27 '13 at 19:21
  • yare, yeare, updated the answer. But i think i should link you the event listeners site. doing wait. – Sage Nov 27 '13 at 19:23
  • This is a bit off topic, but would this animate the splitpane? or would it immediately open the menu? If it doesn't animate, is there a way to do so?? – XQEWR Nov 27 '13 at 19:26
  • @RWEQX, there is always a way. Take a look into [swing timer](http://docs.oracle.com/javase/tutorial/uiswing/misc/timer.html). use it and update your splitpane divider location with timely basis. Well for high performance, efficient technique should be applied. As there might have issue with Layout of component inside splitpane, But that is really out of the scope of this question – Sage Nov 27 '13 at 19:29
2

There are two basic problems...

  1. You need to detect when the mouse hovers over the divider and
  2. When it exists the "menu"

The second is relatively easy, you can use a MouseListener and monitor the mouseExit event, setting the position of the split pane divider as the mouse leaves.

This is complicated though, as if the user exists the "menu" by crossing over the divider, this may trigger the "menu" to made visible again...

The first problem is more complicated, as the JSplitPane contains three components, the left and right components, but also a divider component. JSplitPane doesn't actually allow access to the divider, which is rather annoying and because it uses it's own mouse listener, it blocks mouse events going to the split itself.

Instead, you need to gain access to it via the UI delegate.

Once you've set up the mouse listener, you need to ensure that the menu will only be shown when the menu is hidden, for this, I simply checked the size of the "menu" component

For example...

import java.awt.Color;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Insets;
import java.awt.Rectangle;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.awt.event.MouseMotionAdapter;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JSplitPane;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
import javax.swing.plaf.basic.BasicSplitPaneDivider;
import javax.swing.plaf.basic.BasicSplitPaneUI;

public class TestSpltPane {

    public static void main(String[] args) {
        new TestSpltPane();
    }

    public TestSpltPane() {
        EventQueue.invokeLater(new Runnable() {
            @Override
            public void run() {
                try {
                    UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
                } catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
                    ex.printStackTrace();
                }

                final JPanel left = new JPanel();
                left.setBackground(Color.RED);
                left.setPreferredSize(new Dimension(100, 100));
                JPanel right = new JPanel();
                right.setBackground(Color.BLUE);
                right.setPreferredSize(new Dimension(100, 100));
                final JSplitPane sp = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT, left, right);
                sp.setDividerLocation(0);

                BasicSplitPaneDivider divider = ((BasicSplitPaneUI) sp.getUI()).getDivider();
                divider.addMouseListener(new MouseAdapter() {

                    @Override
                    public void mouseEntered(MouseEvent e) {
                        if (left.getWidth() == 0) {
                            sp.setDividerLocation(100);
                        }
                    }

                });

                left.addMouseListener(new MouseAdapter() {

                    @Override
                    public void mouseExited(MouseEvent e) {
                        sp.setDividerLocation(0);
                    }

                });

                JFrame frame = new JFrame("Testing");
                frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
                frame.add(sp);
                frame.pack();
                frame.setLocationRelativeTo(null);
                frame.setVisible(true);
            }
        });
    }

}
MadProgrammer
  • 343,457
  • 22
  • 230
  • 366