JSplitPane: is there a way to show/hide one of the panes?
I have a JSplitPane with two c开发者_开发百科omponents, 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?
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);
}
}
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);
}
}
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)
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);
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.
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);
}
}
精彩评论