7

I have a JSplitPane with two components, A and B, but sometimes I want to be able to hide B, so that either of the following are true:

  • components A and B are visible in the JSplitPane
  • only component A is visible in the space occupied by the JSplitPane

Is there a way to do this?

Jason S
  • 184,598
  • 164
  • 608
  • 970

6 Answers6

5

Heck, I'll throw in an attempt at a solution...

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

public class Test {
   public static void main(String[] args) {
      JFrame frame = new JFrame();
      final JPanel contentPane = (JPanel)frame.getContentPane();

      final JButton leftBtn = new JButton("Left Button");
      final JButton rightBtn = new JButton("Right Button");
      final JSplitPane jsp = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT,
            leftBtn, rightBtn);
      ActionListener actionListener = new ActionListener() {
         public void actionPerformed(ActionEvent e) {
            JButton source = (JButton)e.getSource();
            if (jsp.isVisible()) {
               jsp.remove(rightBtn);
               jsp.remove(leftBtn);
               jsp.setVisible(false);
               contentPane.removeAll();
               contentPane.add(source);
            } else {
               contentPane.removeAll();
               jsp.setLeftComponent(leftBtn);
               jsp.setRightComponent(rightBtn);
               jsp.setDividerLocation(0.5);
               jsp.setVisible(true);
               contentPane.add(jsp);
            }
            contentPane.revalidate();
            contentPane.repaint();
            source.requestFocusInWindow();
         }
      };
      rightBtn.addActionListener(actionListener);
      leftBtn.addActionListener(actionListener);
      contentPane.add(jsp);
      contentPane.setPreferredSize(new Dimension(800, 600));
      frame.pack();
      frame.setLocationRelativeTo(null);
      frame.setVisible(true);
      jsp.setDividerLocation(0.5);
      frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
   }
}
Hovercraft Full Of Eels
  • 283,665
  • 25
  • 256
  • 373
4

I found problems with Hovercraft Full Of Eels' version and made my own.

Hovercraft Full Of Eels' one works, nevertheless graphical bug appears if you click a button, resize the frame, then click again the button ; also like amol said, you may want the splitter position to remain during the process.

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

import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JSplitPane;
import javax.swing.UIManager;

public class JSplitPaneShowHidePane {
    public static void main(String[] args) {
        JFrame frame = new JFrame();
        JPanel contentPane = (JPanel)frame.getContentPane();

        final JButton leftBtn = new JButton("Left Button");
        final JButton rightBtn = new JButton("Right Button");
        final JSplitPane jsp = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT,
                leftBtn, rightBtn);
        ActionListener actionListener = new ActionListener() {
            private int loc = 0;
            public void actionPerformed(ActionEvent e) {
                JButton source = (JButton)e.getSource();
                if(jsp.getLeftComponent().isVisible() && jsp.getRightComponent().isVisible()){
                    loc = jsp.getDividerLocation();
                    jsp.setDividerSize(0);
                    jsp.getLeftComponent().setVisible(source == leftBtn);
                    jsp.getRightComponent().setVisible(source == rightBtn);
                }else{
                    jsp.getLeftComponent().setVisible(true);
                    jsp.getRightComponent().setVisible(true);
                    jsp.setDividerLocation(loc);
                    jsp.setDividerSize((Integer) UIManager.get("SplitPane.dividerSize"));
                }
            }
        };
        rightBtn.addActionListener(actionListener);
        leftBtn.addActionListener(actionListener);
        contentPane.add(jsp);
        frame.pack();
        frame.setSize(800, 600);
        frame.setLocationRelativeTo(null);
        frame.setVisible(true);
        jsp.setDividerLocation(0.5);
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    }
}
ron190
  • 1,032
  • 1
  • 17
  • 29
  • Good solution! However, I found it necessary to call jsp.setDividerLocation(1.0) after hiding the right component, and jsp.setDividerLocation(0.0) after hiding the left component, to ensure that the visible component continues to fill the window when the user resizes it. – Karl von L Dec 06 '16 at 21:56
1

If you have references to the component A and B you could user JSplitPane.remove() method or JComponent.setVisible(false) method of the component A or B.

Test code:

    final JFrame f = new JFrame();
    final JSplitPane jsp = new JSplitPane();
    final JButton leftB = new JButton("Left: Hide Self");
    final JButton rightB = new JButton("Right: Show Left");
    jsp.setOneTouchExpandable(true);
    leftB.addActionListener(new ActionListener() {
        @Override public void actionPerformed(ActionEvent e) {
            jsp.remove(leftB);
        }
    });
    rightB.addActionListener(new ActionListener() {
        @Override public void actionPerformed(ActionEvent e) {
            jsp.setLeftComponent(leftB);
        }
    });
    jsp.setLeftComponent(leftB);
    jsp.setRightComponent(rightB);
    f.add(jsp);
    f.setSize(800, 600);
    f.setVisible(true);
    f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
user802421
  • 7,465
  • 5
  • 40
  • 63
  • setVisible(false) does not satisfy Jason's second bullet. (component A should occupy all visible space owned by splitpane) – Amol Katdare Jul 26 '11 at 20:56
  • +1 for saying it, but @amol's right -- I tried it and it still leaves the splitter visible. Also when you restore setVisible(true) on that component, the splitter position doesn't restore its original position. – Jason S Jul 26 '11 at 20:58
1

Assume HORIZONTAL_SPLIT split with two components (A on left and B on right)

Here is how you would hide A and let B take up all the splitpane's space


myButton.addActionListener(new ActionListener() {
    @Override
    public void actionPerformed(ActionEvent e) {
        mySplitPane.setDividerSize(0);
        mySplitPane.setDividerLocation(mySplitPane.getLocation().x);
    }
});

To hide component B and show A -


...
  mySplitPane.setDividerLocation(pane.getLocation().x+pane.getSize().width);
...

If you have a vertical split, use similar approach and switch x with y and width with height

For a complete solution, you will have to listen to resize events (if applicable) and recalculate the divider location (which means you will have store the state of what is currently visible somewhere)

Amol Katdare
  • 6,740
  • 2
  • 33
  • 36
0

I use this to toggle a log panel at the bottom of a frame:

private void toggleLogPanel() 
{
  if(m_logPanel.isShowing())
  {
    m_logDimension = m_logPanel.getSize();
    m_splitpane.setBottomComponent(null);
    m_splitpane.setDividerSize(0);
  }
  else
  {
    m_logPanel.setPreferredSize(m_logDimension);
    m_splitpane.setBottomComponent(m_logPanel);
    m_splitpane.setDividerSize(new JSplitpane().getDividerSize());
  }

  m_splitpane.resetToPreferredSizes();
}

This remembers and restores the component size.

Reto Höhener
  • 5,419
  • 4
  • 39
  • 79
0

try ExpandableSplitPane#setOneSideHidden

package com.legendmohe.tool.view;

import java.awt.Component;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.lang.reflect.Field;

import javax.swing.JButton;
import javax.swing.JSplitPane;
import javax.swing.plaf.basic.BasicSplitPaneDivider;
import javax.swing.plaf.basic.BasicSplitPaneUI;

/**
 * Created by legendmohe on 2019/4/16.
 */
public class ExpandableSplitPane extends JSplitPane {

    private HiddenListener mHiddenListener;

    private JButton mLeftButton;

    private JButton mRightButton;

    //////////////////////////////////////////////////////////////////////

    public ExpandableSplitPane() {
    }

    public ExpandableSplitPane(int newOrientation) {
        super(newOrientation);
    }

    public ExpandableSplitPane(int newOrientation, boolean newContinuousLayout) {
        super(newOrientation, newContinuousLayout);
    }

    public ExpandableSplitPane(int newOrientation, Component newLeftComponent, Component newRightComponent) {
        super(newOrientation, newLeftComponent, newRightComponent);
    }

    public ExpandableSplitPane(int newOrientation, boolean newContinuousLayout, Component newLeftComponent, Component newRightComponent) {
        super(newOrientation, newContinuousLayout, newLeftComponent, newRightComponent);
    }

    //////////////////////////////////////////////////////////////////////

    public void setOneSideHidden(Component whichSide, boolean isHidden) {
        if (whichSide == getLeftComponent()) {
            // if right commponent hidden
            if (isRightComponentHidden()) {
                // show right and hide left
                if (isHidden) {
                    clickDividerButton(mLeftButton);
                    clickDividerButton(mLeftButton);
                }
            } else if (isLeftComponentHidden()) {
                // show left
                if (!isHidden) {
                    clickDividerButton(mRightButton);
                }
            } else {
                if (isHidden) {
                    clickDividerButton(mLeftButton);
                }
            }
        } else if (whichSide == getRightComponent()) {
            // if left commponent hidden
            if (isLeftComponentHidden()) {
                // show right and hide left
                if (isHidden) {
                    clickDividerButton(mRightButton);
                    clickDividerButton(mRightButton);
                }
            } else if (isRightComponentHidden()) {
                // show left
                if (!isHidden) {
                    clickDividerButton(mRightButton);
                }
            } else {
                if (isHidden) {
                    clickDividerButton(mRightButton);
                }
            }
        }
    }

    public boolean isSideHidden(Component whichSide) {
        if (whichSide == getLeftComponent()) {
            return isLeftComponentHidden();
        } else if (whichSide == getRightComponent()) {
            return isRightComponentHidden();
        }
        return false;
    }

    @Override
    public void setOneTouchExpandable(boolean expandable) {
        super.setOneTouchExpandable(expandable);
        if (expandable) {
            final BasicSplitPaneUI ui = ((BasicSplitPaneUI) getUI());

            Field keepHidden = null;
            try {
                keepHidden = BasicSplitPaneUI.class.getDeclaredField("keepHidden");
                keepHidden.setAccessible(true);
            } catch (NoSuchFieldException e) {
                e.printStackTrace();
            }
            final Field finalKeepHidden = keepHidden;

            BasicSplitPaneDivider divider = ui.getDivider();
            try {
                Field leftButton = BasicSplitPaneDivider.class.getDeclaredField("leftButton");
                leftButton.setAccessible(true);
                Field rightButton = BasicSplitPaneDivider.class.getDeclaredField("rightButton");
                rightButton.setAccessible(true);

                mLeftButton = (JButton) leftButton.get(divider);
                mRightButton = (JButton) rightButton.get(divider);

                mLeftButton.addActionListener(new ActionListener() {
                    @Override
                    public void actionPerformed(ActionEvent e) {
                        try {
                            boolean keepHidden = (boolean) finalKeepHidden.get(ui);
                            handleActionPerformed(mLeftButton, keepHidden);
                        } catch (IllegalAccessException ex) {
                            ex.printStackTrace();
                        }
                    }
                });
                mRightButton.addActionListener(new ActionListener() {
                    @Override
                    public void actionPerformed(ActionEvent e) {
                        try {
                            boolean keepHidden = (boolean) finalKeepHidden.get(ui);
                            handleActionPerformed(mRightButton, keepHidden);
                        } catch (IllegalAccessException ex) {
                            ex.printStackTrace();
                        }
                    }
                });
            } catch (NoSuchFieldException | IllegalAccessException e) {
                e.printStackTrace();
            }
        } else {
            mRightButton = mLeftButton = null;
        }
    }

    ///////////////////////////////////private///////////////////////////////////

    private void handleActionPerformed(JButton whichButton, boolean keepHidden) {
        if (mHiddenListener != null) {
            if (whichButton == mLeftButton) {
                if (isNoSideHidden() && !keepHidden) {
                    mHiddenListener.onStateChanged(this, getLeftComponent(), true);
                } else if (isRightComponentHidden() && keepHidden) {
                    mHiddenListener.onStateChanged(this, getRightComponent(), false);
                }
            } else if (whichButton == mRightButton) {
                if (isNoSideHidden() && !keepHidden) {
                    mHiddenListener.onStateChanged(this, getRightComponent(), true);
                } else if (isLeftComponentHidden() && keepHidden) {
                    mHiddenListener.onStateChanged(this, getLeftComponent(), false);
                }
            }
        }
    }

    private void clickDividerButton(JButton leftButton) {
        leftButton.doClick();
    }

    private boolean isNoSideHidden() {
        return (getDividerLocation() >= getMinimumDividerLocation()) && (getDividerLocation() <= getMaximumDividerLocation());
    }

    private boolean isLeftComponentHidden() {
        return getDividerLocation() <= getMinimumDividerLocation();
    }

    private boolean isRightComponentHidden() {
        return getDividerLocation() >= getMaximumDividerLocation();
    }

    ///////////////////////////////////listener///////////////////////////////////

    public void setHiddenListener(HiddenListener hiddenListener) {
        mHiddenListener = hiddenListener;
    }

    public interface HiddenListener {
        void onStateChanged(ExpandableSplitPane pane, Component whichSide, boolean hidden);
    }
}
legendmohe
  • 750
  • 7
  • 11