我创建了一个 JPanel,其中包含任意数量的 JLabels,使用左对齐的流布局管理器进行布局。 我们称之为 FlowPanel。
每个 FlowPanel 都有一个深度,我想将任意数量的这些 FlowPanel 堆叠在一起,每个 FlowPanel 缩进一个固定的量 * 深度。 最终目标是在具有垂直滚动条(如果需要(但不具有水平滚动条的 JScrollPane 中显示这些堆叠面板。
我尝试使用GridBagLayout堆叠FlowPanel,虽然很容易让它们垂直堆叠并按照我想要的方式缩进,但我无法弄清楚如何获得正确的宽度。 也就是说,流面板只是从我的主面板的右侧运行,而不注意显示的宽度。
我尝试使用setPreferredSize,setSize,弄乱GridBagConstraint...没有运气。
请帮忙! :)
一些示例代码来演示问题。 此代码有 2 个问题: 1.即使只有几行,行也应保持恒定高度。 2. 当流面板包含太多元素时,行会从屏幕右侧滚动。
public class FlowExample {
public static void main(String[] args) throws Exception {
JFrame frame = new JFrame();
StackPanel stackPanel = new StackPanel();
frame.getContentPane().setLayout(new BorderLayout());
frame.getContentPane().add(
new JScrollPane(stackPanel, JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED, JScrollPane.HORIZONTAL_SCROLLBAR_NEVER),
BorderLayout.CENTER);
frame.setLocation(200, 200);
frame.setSize(300, 300);
frame.setVisible(true);
List<FlowPanel> content = new ArrayList<FlowPanel>();
for (int i = 0; i < 20; i++) {
FlowPanel flowPanel = new FlowPanel((int) (4 * Math.random()));
for (int j = 0; j < (int) (20 * Math.random()); j++) {
flowPanel.add(new JLabel("label " + j));
}
content.add(flowPanel);
stackPanel.layoutGUI(content);
Thread.sleep(1000);
}
System.in.read();
System.exit(0);
}
}
class StackPanel extends JPanel {
public StackPanel() {
setLayout(new BorderLayout());
}
public void layoutGUI(final List<FlowPanel> content) {
if (!SwingUtilities.isEventDispatchThread()) {
SwingUtilities.invokeLater(new Runnable() {
@Override
public void run() {
layoutGUI(content);
}
});
return;
}
JPanel mainPanel = new JPanel();
mainPanel.setLayout(new GridLayout(content.size(), 1));
for (FlowPanel flowPanel : content) {
flowPanel.setBorder(BorderFactory.createEmptyBorder(0, flowPanel.getDepth() * 10, 0, 0));
mainPanel.add(flowPanel);
}
removeAll();
add(mainPanel, BorderLayout.CENTER);
revalidate();
}
}
class FlowPanel extends JPanel {
private int depth;
public FlowPanel(int depth) {
setLayout(new FlowLayout(FlowLayout.LEFT));
this.depth = depth;
}
public int getDepth() {
return depth;
}
}
下面是一些使用 GridBagLayout 布置主面板的示例代码。 这是我得到的最好的结果,但正如你所看到的,FlowPanel仍然没有包装......
JPanel mainPanel = new JPanel();
mainPanel.setLayout(new GridBagLayout());
GridBagConstraints constraints = new GridBagConstraints();
constraints.weightx = 1;
constraints.gridwidth = GridBagConstraints.REMAINDER;
constraints.anchor = GridBagConstraints.LINE_START;
for (FlowPanel flowPanel : content) {
System.out.println("setting border to " + flowPanel.getDepth());
flowPanel.setBorder(BorderFactory.createEmptyBorder(0, flowPanel.getDepth() * 10, 0, 0));
mainPanel.add(flowPanel, constraints);
}
constraints.weighty = 1;
mainPanel.add(new JPanel(), constraints);
removeAll();
add(mainPanel, BorderLayout.CENTER);
revalidate();
GridLayout 试图为您适应屏幕上的所有内容,因此通过向它传递列表,它每次都会重新调整高度。 通过从一开始就设置一个大常量,你告诉它要腾出足够的空间。 尝试修改此行:
mainPanel.setLayout(new GridLayout(content.size(), 1));
自
mainPanel.setLayout(new GridLayout(500, 1));
若要停止从头开始显示滚动条,另一种方法是改用 BoxLayout。
JPanel mainPanel = new JPanel();
Box box = Box.createVerticalBox();
mainPanel.add( box );
for (FlowPanel flowPanel : content) {
flowPanel.setBorder(BorderFactory.createEmptyBorder(0, flowPanel.getDepth() * 10, 0, 0));
box.add(flowPanel);
}
removeAll();
add(mainPanel, BorderLayout.CENTER);
revalidate();
包装问题归结为FlowLayout只关注setPreferredSize。 您可以使用现有代码设置一个首选大小,以动态调整大小要求为代价来适应所有大小。 或者,我过去使用过camickr的WrapLayout,效果很好。
http://tips4java.wordpress.com/2008/11/06/wrap-layout/
照原样,WrapLayout 根据是否需要换行返回不同的首选大小,通过快速破解 WrapLayout.java 来懒洋洋地避免:
1(. 添加最小宽度变量
private int minWidth = -1;
2(. 修改最后一行的"布局大小"方法:
if(minWidth != -1) {
dim.width = minWidth;
}
return dim;
完成后,对示例代码的唯一更改是在 FlowPanel 构造函数中:
public FlowPanel(int depth) {
WrapLayout layout = new WrapLayout(FlowLayout.LEFT);
layout.setMinWidth(300);
setLayout(layout);
setSize(new Dimension(300, 30));
}