【问题标题】:Working with Java layout managers使用 Java 布局管理器
【发布时间】:2012-04-30 23:38:54
【问题描述】:

我创建了一个 JPanel,其中包含任意数量的 JLabel,并使用左对齐的流布局管理器进行布局。让我们称之为 FlowPanel。

每个 FlowPanel 都有一个深度,我想将任意数量的 FlowPanel 堆叠在一起,每一个都缩进一个固定的数量 * 深度。最终的目标是在 JScrollPane 中显示这些堆叠的面板,其中包含垂直滚动条(如果需要)但不包含水平滚动条。

我尝试将 FlowPanel 与 GridBagLayout 堆叠在一起,虽然让它们垂直堆叠并按我想要的方式缩进很容易,但我不知道如何让宽度正确。也就是说,FlowPanel 只是从我的主面板的右侧运行,而不注意显示的宽度。

我尝试过使用 setPreferredSize、setSize,弄乱了 GridBagConstraints……没有运气。

请帮忙! :)

一些示例代码来演示该问题。这段代码有两个问题: 1. 即使只有几行,行的高度也应保持不变。 2.当FlowPanels包含太多元素时,行会从屏幕右侧滚动出来。

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 就足够了),但为每个面板分配了一个仅左侧的空边框?
  • 似乎不起作用...现在编写示例代码进行演示。
  • 当 FlowPanel 比 StackPanel 宽时你想要什么行为?它应该环绕并增加它的深度吗?或者您想在添加尚未达到最大值的 JLabel 时进行测试。宽度了吗?
  • @John Greenhow:如果 FlowPanel 超过 StackPanel 的宽度,它应该环绕并增加 StackPanel 的高度。

标签: java layout gridbaglayout flowlayout


【解决方案1】:

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)。修改最后一行的'layoutSize'方法:

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

【讨论】:

  • 感谢您的帮助!这很棒! :)
  • fyi,我最终在 WrapLayout 中调用了 int“preferredWidth”,然后在其余方法生效之前使用它在“layoutSize”方法的顶部设置“targetSize”。这似乎工作得很好。
  • 同意,这是更好的方法。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2016-06-08
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-06-11
  • 2017-11-02
  • 2010-10-07
相关资源
最近更新 更多