3

I would like to make my JToolBar impossible to detach from its container but still let the user drag it to one of the container's sides.

I know about

public void setFloatable( boolean b )

but this won't allow the user to move the JToolBar at all.

Is there any way of doing this without overwriting ToolBarUI?

Also, is there an option to highlight its new position before dropping it?

Vlad Topala
  • 896
  • 1
  • 8
  • 34

2 Answers2

2
  • works for me quite correctly on WinOS, old code from SunForum

enter image description here

import java.awt.*;
import java.awt.event.*;
import javax.swing.*;

public class CaptiveToolBar {

    private Robot robot;
    private JDialog dialog;
    private JFrame frame;

    public static void main(String[] args) {
        //JFrame.setDefaultLookAndFeelDecorated(true);
        //JDialog.setDefaultLookAndFeelDecorated(true);
        SwingUtilities.invokeLater(new Runnable() {

            @Override
            public void run() {
                new CaptiveToolBar().makeUI();
            }
        });
    }

    public void makeUI() {
        try {
            robot = new Robot();
        } catch (AWTException ex) {
            ex.printStackTrace();
        }
        final JToolBar toolBar = new JToolBar();
        for (int i = 0; i < 3; i++) {
            toolBar.add(new JButton("" + i));
        }
        frame = new JFrame();
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.setSize(400, 400);
        frame.setLocationRelativeTo(null);
        frame.add(toolBar, BorderLayout.NORTH);

        final ComponentListener dialogListener = new ComponentAdapter() {

            @Override
            public void componentMoved(ComponentEvent e) {
                dialog = (JDialog) e.getSource();
                setLocations(false);
            }
        };
        toolBar.addHierarchyListener(new HierarchyListener() {

            @Override
            public void hierarchyChanged(HierarchyEvent e) {
                Window window = SwingUtilities.getWindowAncestor(toolBar);
                if (window instanceof JDialog) {
                    boolean listenerAdded = false;
                    for (ComponentListener listener : window.getComponentListeners()) {
                        if (listener == dialogListener) {
                            listenerAdded = true;
                            break;
                        }
                    }
                    if (!listenerAdded) {
                        window.addComponentListener(dialogListener);
                    }
                }
            }
        });
        frame.addComponentListener(new ComponentAdapter() {

            @Override
            public void componentMoved(ComponentEvent e) {
                if (dialog != null && dialog.isShowing()) {
                    setLocations(true);
                }
            }
        });
        frame.setVisible(true);
    }

    private void setLocations(boolean moveDialog) {
        int dialogX = dialog.getX();
        int dialogY = dialog.getY();
        int dialogW = dialog.getWidth();
        int dialogH = dialog.getHeight();
        int frameX = frame.getX();
        int frameY = frame.getY();
        int frameW = frame.getWidth();
        int frameH = frame.getHeight();
        boolean needToMove = false;
        if (dialogX < frameX) {
            dialogX = frameX;
            needToMove = true;
        }
        if (dialogY < frameY) {
            dialogY = frameY;
            needToMove = true;
        }
        if (dialogX + dialogW > frameX + frameW) {
            dialogX = frameX + frameW - dialogW;
            needToMove = true;
        }
        if (dialogY + dialogH > frameY + frameH) {
            dialogY = frameY + frameH - dialogH;
            needToMove = true;
        }
        if (needToMove) {
            if (!moveDialog && robot != null) {
                robot.mouseRelease(InputEvent.BUTTON1_MASK);
            }
            dialog.setLocation(dialogX, dialogY);
        }
    }
}
mKorbel
  • 109,525
  • 20
  • 134
  • 319
  • Unfortunately it doesn't work for me either on Windows7. Also, isn't relying on the robot a bit too much in production code? – Vlad Topala May 28 '15 at 06:10
  • 1
    @Vlad my screenshot is from JDK7/WIn7, miss any issue, sure isn't designated to production code, must be added/checked MouseMotion and MouseDragged (from JDialog and HierarchyListener), with to consume() is JDialog going out of parents bounds – mKorbel May 28 '15 at 06:44
  • I understand; I initially thought the code was complete. Unfortunately both answers seem a bit hackish to me so I think I'll make a small effort and create a Dockable Panel class which I can use any where. Once it's done I'll add an answer containing the code. – Vlad Topala May 29 '15 at 07:41
  • there must be Dockable Accordion/Ribbon in Swing, for producion code I'd be going this way – mKorbel May 29 '15 at 08:00
2

It's not the most elegant solution, but it works.

public class Example extends JFrame {

    BasicToolBarUI ui;

    Example() {

        JToolBar tb = new JToolBar();
        tb.add(new JButton("AAAAA"));
        tb.setBackground(Color.GREEN);
        ui = (BasicToolBarUI) tb.getUI();

        getContentPane().addContainerListener(new Listener());
        getContentPane().add(tb, BorderLayout.PAGE_START);

        setDefaultCloseOperation(EXIT_ON_CLOSE);
        setSize(300, 300);
        setLocationRelativeTo(null);
        setVisible(true);
    }

    class Listener implements ContainerListener {

        @Override
        public void componentAdded(ContainerEvent e) {}

        @Override
        public void componentRemoved(ContainerEvent e) {

            if (ui.isFloating()) {
                SwingUtilities.invokeLater(new Runnable() {

                    @Override
                    public void run() {

                        ui.setFloating(false, null);
                    }
                }); 
            }
        }
    }

    public static void main(String[] args) {

        new Example();
    }
}

Explanation:

Whenever the toolbar is moving to a floating state, it is instructed not do so. The only problem is that you have to wait for the EDT to finish the process for creating the floating window, and only then can you tell it not to float. The result is that you actually see the window created and then hidden.

Note:

I think that overriding the UI for the toolbar is a better solution, though it's possible that with a more intricate approach doing something similar to what I did will also work well.

user1803551
  • 12,965
  • 5
  • 47
  • 74
  • Indeed the fact that it shows up and then disappears is kind of annoying and overriding the UI isn't something I'm keen on doing but the example is very useful anyway. – Vlad Topala May 29 '15 at 07:43
  • @Vlad The only approaches you have for the toolbar is either adding listeners to it and controlling the operation through there or extending its UI class. – user1803551 May 29 '15 at 11:17