JSplitPane:有没有一种方法可以显示/隐藏其中一个面板?

7

我有一个包含两个组件A和B的JSplitPane,但有时我想隐藏B,使得以下情况之一成立:

  • 组件A和B都在JSplitPane中可见
  • 只有组件A在JSplitPane占据的空间中可见

有没有方法可以实现这个功能?

6个回答

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);
   }
}

喜欢你的例子+1,source.requestFocusInWindow(); 将被包装进 invokeLater - mKorbel

4
我发现Hovercraft Full Of Eels的版本存在问题,所以我制作了自己的版本。
Hovercraft Full Of Eels的版本可以工作,但是如果你点击一个按钮、重新调整框架大小,然后再次点击按钮,会出现图形错误;此外,就像Amol所说,你可能希望在过程中保留分隔条位置。
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);
    }
}

不错的解决方案!但是,我发现需要在隐藏右侧组件后调用jsp.setDividerLocation(1.0),并在隐藏左侧组件后调用jsp.setDividerLocation(0.0),以确保可见组件继续在用户调整窗口大小时填充窗口。 - Karl von L

1
如果您有组件A和B的引用,可以使用JSplitPane.remove()方法或者组件A或B的JComponent.setVisible(false)方法
测试代码:
    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);

setVisible(false) 不满足Jason的第二个要求。(组件A应占据拆分窗格所拥有的所有可见空间) - Amol Katdare
+1 表示同意,但 @amol 是正确的 - 我尝试过了,它仍然会留下分隔符可见。而且当你在该组件上恢复 setVisible(true) 时,分隔符位置不会恢复其原始位置。 - Jason S
看看Hovercraft Full Of Eels的代码。似乎组件需要重新分配,哈哈。 - user802421

1

假设使用HORIZONTAL_SPLIT分割,有两个组件(左侧为A,右侧为B)

以下是如何隐藏A并让B占据整个分割面板空间的方法


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

隐藏组件B并显示A -

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

如果您有垂直分割,请使用类似的方法,将x替换为y,将width替换为height 对于完整的解决方案,您需要监听调整大小事件(如果适用),并重新计算分隔符位置(这意味着您必须在某个地方存储当前可见内容的状态)

什么是 pane,它是分割窗格吗? - maq

0

我使用这个来在框架底部切换日志面板:

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();
}

这将记住并恢复组件的大小。


0
尝试使用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);
    }
}

我会尝试一下,但这个问题是8年前我在另一家公司时提出的。 - Jason S

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接