我正在尝试开发一种手风琴菜单 . 可以打开/关闭少量(2-12)选项 . 当切换时,会有一个 JPanel
,其他设置变得可见 . 切换时,其他设置将不可见 .
我创建了一个 SelectableExpandablePanel
类,它扩展了 JPanel
并实现了 ActionListener
和 ComponentListener
. 该小组持有两件事 - 一个 JToggleButton
和一个孩子 Component
(通常是一个JPanel,但我不想限制自己将来重复使用这个概念)在 BoxLayout
中强制执行一个列 . 选择切换按钮后,子项变为可见 . 取消选择切换后,将隐藏子项 .
当我使用这个组件时,我打算将它放在 JScrollPane
的 JPanel
内,如示例main方法中所示 .
似乎有两个问题我无法克服:
-
如果我没有指定
JFrame
尺寸,它只对每个孩子的宽度足够大,并且对于三个按钮来说足够高 . 当我点击按钮时,我希望JScrollPane
做它的事情并生成一个垂直滚动条 . 这不会发生 . -
我希望切换按钮是包含它们的JPanel的整个宽度 . 我认为我在构造函数中加上
Component Listener
会处理它,但事实并非如此 .
下面提供的内容编译并有一个主要方法 . 如果编译和执行,它会驱动我正在构建的组件,以提供测试框架和重现我正在谈论的问题的能力 .
import javax.swing.BoxLayout;
import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JToggleButton;
import java.awt.Dimension;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.ComponentEvent;
import java.awt.event.ComponentListener;
public class SelectableExpandablePanel extends JPanel implements
ActionListener, ComponentListener {
private JToggleButton titleButton;
private JComponent childComponent;
public SelectableExpandablePanel(JComponent child) {
this(child, null, null);
}
public SelectableExpandablePanel(JComponent child, String title) {
this(child, title, null);
}
public SelectableExpandablePanel(JComponent child, String title,
String tooltip) {
super();
if (child == null) {
throw new IllegalArgumentException("Child component cannot be null");
}
childComponent = child;
titleButton = new JToggleButton();
titleButton.setText(title);
titleButton.addActionListener(this);
titleButton.setPreferredSize(new Dimension(getSize().width, titleButton
.getPreferredSize().height));
titleButton.setToolTipText(tooltip);
setLayout(new BoxLayout(this, BoxLayout.Y_AXIS));
setPreferredSize(new Dimension(childComponent.getPreferredSize().width,
titleButton.getPreferredSize().height));
setSize(new Dimension(childComponent.getPreferredSize().width,
titleButton.getPreferredSize().height));
add(titleButton);
this.addComponentListener(this);
}
public void actionPerformed(ActionEvent e) {
if (titleButton.isSelected()) {
add(childComponent);
setSize(new Dimension(childComponent.getPreferredSize().width,
titleButton.getPreferredSize().height
+ childComponent.getPreferredSize().height));
} else {
remove(childComponent);
setSize(new Dimension(childComponent.getPreferredSize().width,
titleButton.getPreferredSize().height));
}
invalidate();
revalidate();
}
public void componentHidden(ComponentEvent arg0) {
// Do nothing
}
public void componentMoved(ComponentEvent arg0) {
// Do nothing
}
public void componentResized(ComponentEvent arg0) {
titleButton.setSize(this.getWidth(),
titleButton.getPreferredSize().height);
}
public void componentShown(ComponentEvent arg0) {
// Do nothing
}
public static void main(String[] args) {
JScrollPane scrollPane = new JScrollPane();
// These panels simulates a complex, multi-line configuration panel.
JPanel testPanel = new JPanel();
testPanel.setLayout(new BoxLayout(testPanel, BoxLayout.Y_AXIS));
testPanel.add(new JLabel("Test JLabel"));
testPanel.add(new JLabel("Test JLabel 2"));
testPanel.add(new JLabel("Test JLabel 3"));
JPanel testPanel2 = new JPanel();
testPanel2.setLayout(new BoxLayout(testPanel2, BoxLayout.Y_AXIS));
testPanel2.add(new JLabel("Test JLabel"));
testPanel2.add(new JLabel("Test JLabel 2"));
testPanel2.add(new JLabel("Test JLabel 3"));
JPanel testPanel3 = new JPanel();
testPanel3.setLayout(new BoxLayout(testPanel3, BoxLayout.Y_AXIS));
testPanel3.add(new JLabel("Test JLabel"));
testPanel3.add(new JLabel("Test JLabel 2"));
testPanel3.add(new JLabel("Test JLabel 3"));
// This panel simulates the panel that will contain each of the
// SelectableExpandablePanels.
JPanel testHolder = new JPanel();
testHolder.setLayout(new BoxLayout(testHolder, BoxLayout.Y_AXIS));
testHolder.add(new SelectableExpandablePanel(testPanel, "Test"));
testHolder.add(new SelectableExpandablePanel(testPanel2, "Test 2"));
testHolder.add(new SelectableExpandablePanel(testPanel3, "Test 3"));
// We add the test holder to the scroll pane. The intention is that if
// the expansion is too big to fit, the holding JFrame won't expand, but
// the scroll pane will get scroll bars to let the user scroll up and
// down through the toggle buttons and any enabled items.
scrollPane.setViewportView(testHolder);
JFrame testFrame = new JFrame("Expandable Panel Test");
testFrame.getContentPane().add(scrollPane);
testFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
testFrame.pack();
testFrame.setVisible(true);
}
}
2 回答
不要试图自己管理尺寸:
另外,摆脱ActionListener中的
setSize()
代码 . 无论如何,这将被忽略,因为布局管理器将确定大小 .当面板的首选大小大于滚动窗格的大小时,将出现滚动条 . 如果您对首选大小进行硬编码,则默认布局管理器的用途,并且在添加/删除组件时,首选大小不会更改 .
注意这样的事情我通常使用BorderLayout . 将按钮放在PAGE_START中,将另一个面板放在CENTER中 . 组件将自动填充可用空间 .
删除所有setSize / setPreferredSize调用,让LayoutManager完成它的操作 .
要允许JButtons填充面板的宽度,可以使用BorderLayout(例如,将按钮添加到CENTER,将子容器添加到SOUTH并删除所有这些setSize值以让LayoutManager处理它) .