7

In a JSplitPane, you have the setOneTouchExpandable method which provides you with 2 buttons to quickly fully hide or full show the JSplitPane.

My question is how can you programmatically "click" the hide button on the JSplitPane?

I may have wrongly explained myself. I want the splitpane to show only one of the 2 components at start (this is what i mean by clicking).

This works:

import javax.swing.*;

class SplitPaneDefault {
    public static void main(String[] args) {
        SwingUtilities.invokeLater(new Runnable() {
            public void run() {
                JSplitPane sp = new JSplitPane(
                    JSplitPane.HORIZONTAL_SPLIT,
                    new JTree(),
                    new JTree());
                sp.setOneTouchExpandable(true);
                sp.setDividerLocation(0.0);
                JOptionPane.showMessageDialog(null, sp);
            }
        });
    }
}

but replacing 0.0 with 1.0 doesn't hide the right component. This is my problem!

Adel Boutros
  • 10,205
  • 7
  • 55
  • 89

6 Answers6

6
import javax.swing.*;

class SplitPaneDefault {
    public static void main(String[] args) {
        SwingUtilities.invokeLater(new Runnable() {
            public void run() {
                JSplitPane sp = new JSplitPane(
                    JSplitPane.HORIZONTAL_SPLIT,
                    new JTree(),
                    new JTree());
                sp.setOneTouchExpandable(true);
                sp.setDividerLocation(0.0);
                JOptionPane.showMessageDialog(null, sp);
            }
        });
    }
}

replace 0.0 with 1.0 and you get my problem

Read the fine manual and solve the problem.

This method immediately changes the size of the split pane based on its current size. If the split pane is not correctly realized and on screen, this method will have no effect ...

SplitPaneDefault

import javax.swing.*;

class SplitPaneDefault {
    public static void main(String[] args) {
        SwingUtilities.invokeLater(new Runnable() {
            public void run() {
                JSplitPane sp = new JSplitPane(
                    JSplitPane.HORIZONTAL_SPLIT,
                    new JTree(),
                    new JTree());
                sp.setOneTouchExpandable(true);
                JFrame f = new JFrame("Split Pane To Right");
                f.add(sp);
                f.pack();
                // sp now has a non-zero size!
                sp.setDividerLocation(1.0);
                f.setLocationByPlatform(true);
                f.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
                f.setVisible(true);
            }
        });
    }
}
Andrew Thompson
  • 168,117
  • 40
  • 217
  • 433
  • replace 0.0 with 1.0 and you get my problem :) – Adel Boutros Feb 07 '12 at 13:57
  • 3
    @AdelBoutros, there is nothing wrong with asking people to read the documentation. Your question was not very clear. You updated the question to make it clearer as people asked for more information. This is not the best use of our time to continually return to a question for updated information. I would have lost patience long ago. All the information should be in the question from the start. Learn from this question and move on. – camickr Feb 07 '12 at 16:20
4

Here is another solution, maybe a little bit dirty, but it works ;) I hope the code speaks for itself.

public class ExtOneTouchJSplitPane extends JSplitPane {
    private static final long serialVersionUID = -2320161961382260438L;

    JButton jBLeftUp;
    JButton jBRightDown;

    public ExtOneTouchJSplitPane() {
        super();
        setOneTouchExpandable(true);
        extractDividerButtons();
    }

    public ExtOneTouchJSplitPane(int newOrientation) {
        super(newOrientation);
        setOneTouchExpandable(true);
        extractDividerButtons();
    }

    public ExtOneTouchJSplitPane(int newOrientation, boolean newContinuousLayout) {
        super(newOrientation, newContinuousLayout);
        setOneTouchExpandable(true);
        extractDividerButtons();
    }

    public ExtOneTouchJSplitPane(int newOrientation, boolean newContinuousLayout, Component newLeftComponent, Component newRightComponent) {
        super(newOrientation, newContinuousLayout, newLeftComponent, newRightComponent);
        setOneTouchExpandable(true);
        extractDividerButtons();
    }

    public ExtOneTouchJSplitPane(int newOrientation, Component newLeftComponent, Component newRightComponent) {
        super(newOrientation, newLeftComponent, newRightComponent);
        setOneTouchExpandable(true);
        extractDividerButtons();
    }

    private void extractDividerButtons() {
        BasicSplitPaneUI ui = (BasicSplitPaneUI) getUI();
        jBLeftUp = (JButton) ui.getDivider().getComponent(0);
        jBRightDown = (JButton) ui.getDivider().getComponent(1);
    }

    public void oneTouchClickLeft() {
        jBLeftUp.doClick();
    }

    public void oneTouchClickRight() {
        jBRightDown.doClick();
    }

    public void oneTouchClickUp() {
        jBLeftUp.doClick();
    }

    public void oneTouchClickDown() {
        jBRightDown.doClick();
    }
}

And an example how to use it:

public class SplitPaneDemo extends JFrame implements Runnable {

    public static void main(String[] args) {
        SwingUtilities.invokeLater(new SplitPaneDemo());
    }

    ExtOneTouchJSplitPane hSplitPane;
    ExtOneTouchJSplitPane vSplitPane;

    public SplitPaneDemo() {
        createView();
    }

    public void createView() {
        setTitle("SplitPane-Demo");
        setLayout(new BorderLayout(0, 0));

        hSplitPane = new ExtOneTouchJSplitPane();
        JButton jBLeft = new JButton("<html><body> &nbsp;<br>Left Component<br> &nbsp;</body></html>");
        JButton jBRight = new JButton("<html><body> &nbsp;<br>Right Component<br> &nbsp;</body></html>");
        jBLeft.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                hSplitPane.oneTouchClickLeft();
            }
        });
        jBRight.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                hSplitPane.oneTouchClickRight();
            }
        });
        hSplitPane.setLeftComponent(jBLeft);
        hSplitPane.setRightComponent(jBRight);

        add(hSplitPane, BorderLayout.CENTER);

        vSplitPane = new ExtOneTouchJSplitPane(JSplitPane.VERTICAL_SPLIT);
        JButton jBUp = new JButton("<html><body> &nbsp;<br>Up Component<br> &nbsp;</body></html>");
        JButton jBDown = new JButton("<html><body> &nbsp;<br>Down Component<br> &nbsp;</body></html>");
        jBUp.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                vSplitPane.oneTouchClickUp();
            }
        });
        jBDown.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                vSplitPane.oneTouchClickDown();
            }
        });
        vSplitPane.setTopComponent(jBUp);
        vSplitPane.setBottomComponent(jBDown);

        add(vSplitPane, BorderLayout.SOUTH);
    }

    @Override
    public void run() {
        setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
        setSize(400, 400);
        setVisible(true);

        hSplitPane.oneTouchClickLeft();
    }
}
Dirk
  • 41
  • 2
3

You can simply use this:

public void setDividerLocation(double proportionalLocation)

splitPane.setDividerLocation(0.0d);

or.

splitPane.setDividerLocation(1.0d);

depending on wheter yourwant to hide the left component first or the right component.

Guillaume Polet
  • 47,259
  • 4
  • 83
  • 117
  • 1
    It didn't work, I tried it. with the `0.0d`, it works by hiding the top part. But `1.0d` doesn't hide the bottom part, it still shows a big part of it. Is this normal? – Adel Boutros Feb 07 '12 at 13:54
  • It worked when I tried it in an SSCCE (shown in answer). How about *you* show us an SSCCE that behaves differently? – Andrew Thompson Feb 07 '12 at 13:55
1

Working around the problem that setDividerLocation(1.0) doesn't work until the frame has become displayable, one can use an AncestorListener:

sp.addAncestorListener(new AncestorListener {
  def ancestorAdded  (event: AncestorEvent): Unit = sp.setDividerLocation(1.0)

  def ancestorRemoved(event: AncestorEvent): Unit = ()
  def ancestorMoved  (event: AncestorEvent): Unit = ()
})
0__
  • 66,707
  • 21
  • 171
  • 266
1

@0__'s answer is a hint that you should be using the AncestorListener to set the divider location, and have it taken into account (ComponentListener is not enough, I'm not sure why).

However, it's not sufficient: if the split plane somehow gets resized (e.g. because its layout manager decided it should, when the frame has been resized), a tiny fraction of the component you wanted to hide will still show. That's due to the component minimum size not being zero. It can be addressed by zeroing it with setMinimumSize(new Dimension()) (as explained in that other answer), but if that's not an option, you can hack into the split pane UI:

If you're using the standard BasicSplitPaneUI, you can hack its keepHidden boolean field and force it to true, so the divider will stick to either side:

sp.addAncestorListener(new AncestorListener() {
    @Override
    public void ancestorAdded(AncestorEvent event) {
        sp.setDividerLocation(1.0); // Divider is positioned
        Field m = BasicSplitPaneUI.class.getDeclaredField("keepHidden");
        m.setAccessible(true);
        m.set(sp.getUI(), true); // Divider position will stick
        //sp.removeAncestorListener(this); // Uncomment for a one-shot event
    }

    @Override public void ancestorRemoved(AncestorEvent event) { }
    @Override public void ancestorMoved(AncestorEvent event) { }
});
Community
  • 1
  • 1
Matthieu
  • 2,736
  • 4
  • 57
  • 87
0

Combining other answers, doClick and the delay via AncestorListener worked for me. See explanation:

if (wantHiddenPane) {
  // The splitPane's "onload" event approximation =
  // the hierarchy ancestor changes when the pane gets packed/made visible on screen
  // Which is when the splitPane dimensions have been initialized based on available screen space
  // So that edits to the divider location can take effect after that.
   splitPane.addAncestorListener(new AncestorListener() {
       public void ancestorAdded(AncestorEvent ev) {
          // Pressing the oneTouch button shows/hides a pane while remembering the last custom dragged size
          BasicSplitPaneUI ui = (BasicSplitPaneUI) splitPane.getUI();
          JButton neededOneTouchBtn = (JButton) ui.getDivider().getComponent(isHiddenPaneLeftTop ? 0 : 1);
          neededOneTouchBtn.doClick();
        }
        // only run once
         splitPane.removeAncestorListener(this);
       }

       public void ancestorRemoved(AncestorEvent ev) {
       }

       public void ancestorMoved(AncestorEvent ev) {
       }
     });
 }
Michelle Norris
  • 568
  • 7
  • 14