2

When I hide a node of the JXMultiSplitPane, I encounter painting issues. The following SSCCE illustrates this behaviour:

import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;

import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.SwingUtilities;

import org.jdesktop.swingx.JXMultiSplitPane;
import org.jdesktop.swingx.MultiSplitLayout;
import org.jdesktop.swingx.MultiSplitLayout.Divider;
import org.jdesktop.swingx.MultiSplitLayout.Leaf;
import org.jdesktop.swingx.MultiSplitLayout.Node;
import org.jdesktop.swingx.MultiSplitLayout.Split;

public class TestMultiSplitPane {

    public static final String LEFT = "left";
    public static final String CENTER = "center";
    public static final String RIGHT = "right";

    public static final String TOP = "top";
    public static final String MIDDLE = "middle";
    public static final String BOTTOM = "bottom";

    protected void initUI() {
        JFrame frame = new JFrame();
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        Split horizontal = new Split();
        Split left = getVerticalSplit(LEFT, 0.5, 0.5);
        left.setWeight(0.2);
        Split center = getVerticalSplit(CENTER, 0.8, 0.2);
        center.setWeight(0.6);
        Split right = getVerticalSplit(RIGHT, 0.5, 0.5);
        right.setWeight(0.2);
        horizontal.setChildren(left, new Divider(), center, new Divider(), right);
        MultiSplitLayout layout = new MultiSplitLayout(horizontal);
        JXMultiSplitPane splitPane = new JXMultiSplitPane(layout);
        addButton(LEFT + TOP, splitPane);
        addButton(CENTER + TOP, splitPane);
        addButton(RIGHT + TOP, splitPane);
        addButton(LEFT + BOTTOM, splitPane);
        addButton(CENTER + BOTTOM, splitPane);
        addButton(RIGHT + BOTTOM, splitPane);
        frame.add(splitPane);
        frame.setBounds(50, 50, 1024, 768);
        frame.setVisible(true);
    }

    protected void addButton(final String buttonName, final JXMultiSplitPane splitPane) {
        final JButton button = new JButton(buttonName);
        splitPane.add(buttonName, button);
        button.addActionListener(new ActionListener() {

            @Override
            public void actionPerformed(ActionEvent e) {
                MultiSplitLayout layout = splitPane.getMultiSplitLayout();
                Node node = layout.getNodeForName(buttonName);
                Split parent = node.getParent();
                parent.hide(node);
                splitPane.invalidate();
                splitPane.revalidate();
                splitPane.repaint();
            }
        });
    }

    public Split getVerticalSplit(String name, double topWeight, double bottomWeight) {
        Split split = new Split();
        split.setRowLayout(false);
        Leaf top = new Leaf(name + TOP);
        top.setWeight(topWeight);
        Leaf bottom = new Leaf(name + BOTTOM);
        bottom.setWeight(bottomWeight);
        split.setChildren(top, new Divider(), bottom);
        return split;
    }

    public static void main(String[] args) {
        SwingUtilities.invokeLater(new Runnable() {

            @Override
            public void run() {
                new TestMultiSplitPane().initUI();

            }
        });
    }

}

You can click on any button displayed and it should get hidden but the repainting of the splitpane is problematic as I move my mouse over the different buttons.

For those who use Maven, here is the required dependency:

    <dependency>
        <groupId>org.swinglabs.swingx</groupId>
        <artifactId>swingx-core</artifactId>
        <version>1.6.3</version>
    </dependency>
Guillaume Polet
  • 47,259
  • 4
  • 83
  • 117

2 Answers2

1

I know it's been a while since you asked the question but I searched a lot until I found a solution (not a great one though) and maybe this will help someone.
I do a lot of add/remove components in the panels I add to the splitPane and if I resized a splitter before adding components it got stuck there and either cut out part of my panel or get to big.

As it says in the documentation:

MultiSplitLayout's "floatingDividers" property, initially true, is set to false by the MultiSplitPane as soon as any Divider is repositioned. When floatingDividers is false, the right/bottom edge of each Leaf (component) is defined by the location of the Divider that follows it. In other words, once the user moves a Divider, the layout no longer depends on the preferred size of any components, it's defined by the current position of the Dividers and the weights.

What I did was call the setFloatingDividers(true) method on each resize I did (resizes related to add/remove components). The problem that arises from this is that the position of the splitters is lost.

Vlad Topala
  • 896
  • 1
  • 8
  • 34
  • Before adding components to my panel I called: multiSplitPane.getMultiSplitLayout().setFloatingDividers(true); This way the dividers move according to the preferred sizes. The problem is you can't set only one divider to floating. – Vlad Topala Mar 14 '13 at 13:54
  • I posted a much simpler solution and which is very much reliable. Thanks for your efforts in considering this question though. – Guillaume Polet Mar 14 '13 at 13:56
  • I read it and it really is simpler but unfortunately in my case I don't want to hide a whole node just components from the contained panel. Here's a short example: I currently have 3 rows of buttons in the panel contained by my node I move the bottom splitter as high as possible On an action event I add 3 more rows => The 3 added rows will be hidden because the bottom splitter is fix. The problem with setting floating divider to true is that if I have a column of 4 nodes all the splitters will reposition and not just the one I wanted. – Vlad Topala Mar 14 '13 at 13:59
  • Ok, I didn't know that you also had an issue with multi-split pane. Don't hesitate to post a new question on this matter. kleopatra is there from time to time, and I expect that she knows a lot more about it since she contributes to SwingX. – Guillaume Polet Mar 14 '13 at 14:02
1

I eventually found the solution. To hide a node in the layout, we can simply use the method displayNode(String, boolean).

Therefore, in the actionPerformed, all I needed to call was this:

layout.displayNode(buttonName, false);

The fully working code:

import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;

import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.SwingUtilities;

import org.jdesktop.swingx.JXMultiSplitPane;
import org.jdesktop.swingx.MultiSplitLayout;
import org.jdesktop.swingx.MultiSplitLayout.Divider;
import org.jdesktop.swingx.MultiSplitLayout.Leaf;
import org.jdesktop.swingx.MultiSplitLayout.Split;

public class TestMultiSplitPane {

    public static final String LEFT = "left";
    public static final String CENTER = "center";
    public static final String RIGHT = "right";

    public static final String TOP = "top";
    public static final String MIDDLE = "middle";
    public static final String BOTTOM = "bottom";

    protected void initUI() {
        JFrame frame = new JFrame();
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        Split horizontal = new Split();
        Split left = getVerticalSplit(LEFT, 0.5, 0.5);
        left.setWeight(0.2);
        Split center = getVerticalSplit(CENTER, 0.8, 0.2);
        center.setWeight(0.6);
        Split right = getVerticalSplit(RIGHT, 0.5, 0.5);
        right.setWeight(0.2);
        horizontal.setChildren(left, new Divider(), center, new Divider(), right);
        MultiSplitLayout layout = new MultiSplitLayout(horizontal);
        JXMultiSplitPane splitPane = new JXMultiSplitPane(layout);
        addButton(LEFT + TOP, splitPane);
        addButton(CENTER + TOP, splitPane);
        addButton(RIGHT + TOP, splitPane);
        addButton(LEFT + BOTTOM, splitPane);
        addButton(CENTER + BOTTOM, splitPane);
        addButton(RIGHT + BOTTOM, splitPane);
        frame.add(splitPane);
        frame.setBounds(50, 50, 1024, 768);
        frame.setVisible(true);
    }

    protected void addButton(final String buttonName, final JXMultiSplitPane splitPane) {
        final JButton button = new JButton(buttonName);
        splitPane.add(buttonName, button);
        button.addActionListener(new ActionListener() {

            @Override
            public void actionPerformed(ActionEvent e) {
                MultiSplitLayout layout = splitPane.getMultiSplitLayout();
                layout.displayNode(buttonName, false);
            }
        });
    }

    public Split getVerticalSplit(String name, double topWeight, double bottomWeight) {
        Split split = new Split();
        split.setRowLayout(false);
        Leaf top = new Leaf(name + TOP);
        top.setWeight(topWeight);
        Leaf bottom = new Leaf(name + BOTTOM);
        bottom.setWeight(bottomWeight);
        split.setChildren(top, new Divider(), bottom);
        return split;
    }

    public static void main(String[] args) {
        SwingUtilities.invokeLater(new Runnable() {

            @Override
            public void run() {
                new TestMultiSplitPane().initUI();

            }
        });
    }
}
Guillaume Polet
  • 47,259
  • 4
  • 83
  • 117