2

我正在寻找一个布局管理器(或一组布局管理器)来帮助我垂直排列我的组件。所有组件(按钮)都应具有相同的宽度,并以底层对话框客户区宽度为边界。这些按钮中的每一个都能够根据连接的 JLabel 扩展其高度(一旦用户单击相关按钮,标签将显示) - 简而言之:所有组件都应拉伸到相同的固定宽度,但具有变量高度取决于它们的内容。如果需要,整个对话框内容应放置在 JScrollPane 中以支持垂直滚动条。

我在这一点上,我堆叠了许多不同的布局管理器(主要是用于水平拉伸的边界布局和用于垂直排列的框布局)来实现我的目标行为。但它既不是令人满意的代码,也不能完全按照我的意愿工作。

我花了很多时间在网上浏览这个问题,发现垂直布局是 Java 中的一个常见问题。很多人回答说 GridBagLayout 将是完成这项工作的最佳布局,但我没有让它按照我想要的方式工作。

我希望这些信息足以为我解决这个问题提供一些帮助。

最好的问候迈克尔

编辑:-不再需要-

编辑2:

这是我当前尝试的图像: http ://www.pic-upload.de/view-16978954/example-image.png.html

这几乎是我想要的结果,但在调整大小时有奇怪的行为。

编辑3:

我认为我的主要问题是 JScrollPane 与包含 JLabel 的 html 相结合,我需要 setMaximumSize(...) 之类的东西,但它不能正常工作: http ://www.pic-upload.de/view- 16988005/example-image3.png.html

我需要一个固定的宽度,但我找不到设置它的方法。

setPreferredSize(...) 有效,但我不知道 JLabel 的高度,因为它包含 html 文本。

编辑4:

我的按钮:

public class Expander extends JPanel implements ActionListener {

    private static class HtmlViewer extends JLabel {

        private static final long serialVersionUID = 8787130155299083869L;


        public HtmlViewer(String doc) {
            super(doc);
            this.setBackground(Color.WHITE);
            this.setOpaque(true);
        }
    }


    private static final long serialVersionUID = 4480221797736558685L;


    JToggleButton button;
    JComponent component;


    public Expander(String text, String doc) {
        this(text, new HtmlViewer(doc));
    }

    public Expander(String text, JComponent expandableComponent) {
        this.setLayout(new BorderLayout());

        button = new JToggleButton(text) {
            private static final long serialVersionUID = -3330376265192275758L;

            @Override
            public void paint(Graphics g) {
                super.paint(g);

                if (this.isSelected()) {
                    g.drawString("▼", this.getWidth() - 20, 15);
                } else {
                    g.drawString("■", this.getWidth() - 20, 15);
                }
            }
        };

        button.setFocusPainted(false);
        button.addActionListener(this);

        component = expandableComponent;
        component.setBorder(new EmptyBorder(5, 5, 5, 5));

        this.add(button, BorderLayout.PAGE_START);
    }


    @Override
    public void actionPerformed(ActionEvent e) {
        if (button.isSelected()) {
            this.add(component);
        } else {
            this.remove(component);
        }
        this.getTopLevelAncestor().validate();
        this.getTopLevelAncestor().repaint();
        this.setMaximumSize(this.getPreferredSize());
    }
}

框架:

public class grid2 {

    public static void main(String[] args) {

        final JFrame frame = new JFrame();
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

        JPanel p = new JPanel();
        JScrollPane scroll = new JScrollPane(p, JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED, ScrollPane.HORIZONTAL_SCROLLBAR_NEVER);
        addStuff(p);

        frame.add(scroll);

        frame.pack();
        frame.setVisible(true);
    }

    public static void addStuff(Container container) {
        container.setLayout(new GridBagLayout());

        GridBagConstraints c = new GridBagConstraints();
        c.fill = GridBagConstraints.HORIZONTAL;
        c.weightx = 1;
        c.weighty = 0;

        Expander e = new Expander("test", "<html>fgb fdh fgfhg ifghiufdshfidsghfiufdsghiudsfhdsfiu dshiufhds if dhf idsufhdsiufhiufhiuds hfdshfiudshfuidsifudshfiudshf  ufdhfiushdfiudshiufhdsiufhdsiuf udshfiudshfiudshfudshf iuhfiudshfiudshfiudshf</html>"); // long html text example
        e.setMaximumSize(new Dimension(500, 10000));
        c.gridx = 0;
        c.gridy = 0;
        c.gridwidth = GridBagConstraints.REMAINDER;
        container.add(e, c);

        JButton button2 = new JButton("Button 2");
        c.gridy = 1;
        c.gridwidth = GridBagConstraints.REMAINDER;
        container.add(button2, c);

        c.gridy = 2;
        c.weighty = 1;
        c.gridwidth = GridBagConstraints.REMAINDER;
        container.add(new JLabel(), c);
    }
}
4

4 回答 4

3

请参阅http://docs.oracle.com/javase/tutorial/uiswing/layout/box.html

setLayout(new BoxLayout(pane, BoxLayout.Y_AXIS));

例子

于 2012-11-20T15:24:27.170 回答
2

我会使用的是GridBagLayout。它类似于 HTML 表格,通过使用GridBagConstraints,您可以将对象设置为在水平和垂直方向上展开(例如constraints.fill = GridBagConstraints.BOTH

我相信这可以解决您在下图中的问题(有一个小技巧可以通过在底部添加一个空白标签使按钮保持在顶部,但我相信通过更多的修补可以将其删除)

public static void main(String[] args) {
    final JFrame frame = new JFrame();
    frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

    addStuff(frame.getContentPane());

    frame.pack();
    frame.setVisible(true);
}

public static void addStuff(Container container) {
    container.setLayout(new GridBagLayout());

    GridBagConstraints c = new GridBagConstraints();
    c.fill = GridBagConstraints.HORIZONTAL;
    c.weightx = 1;
    c.weighty = 0;

    JButton button = new JButton("Button 1");
    c.gridx = 0;
    c.gridy = 0;
    container.add(button, c);

    JButton button2 = new JButton("Button 2");
    c.gridy = 1;
    container.add(button2, c);

    c.gridy = 2;
    c.weighty = 1;
    container.add(new JLabel(), c);
}
于 2012-11-20T15:24:33.707 回答
1

好的,我让它工作了。我完全错了,我认为 JScrollPane 是这个问题的麻烦制造者,但它是 JLabel。如果 JLabel 包含 HTML 文本,它不会自动换行文本,这就是如果对话框的宽度太小,所有内容都会水平拉伸的原因。我在这里找到了解决这个问题的好方法:通过设置最大宽度使 JLabel 包装它的文本

答案 6:

JLabel labelBeingUsed = myLabel;
View view = (View) labelBeingUsed.getClientProperty(BasicHTML.propertyKey);
view.setSize(scrollPane1.getWidth(), 0.0f);
float w = view.getPreferredSpan(View.X_AXIS);
float h = view.getPreferredSpan(View.Y_AXIS);
labelBeingUsed.setSize((int) w, (int) h);

每次调整对话框大小时,都需要使用上面的代码将每个包含 JLabel 的 HTML 的宽度更新为所需的宽度。

非常感谢您提供的所有有用提示。

于 2012-11-22T09:12:12.217 回答
1

这里有几个问题:

  1. 会伸展你BorderLayoutJFrameJPanel p
  2. 您没有设置weightx,因此该fill属性无用

解决方案:

  1. 要么将您包装JPanel p在另一个将其放在顶部的面板中,要么在最后添加一个额外的不可见 JPanel 以推动您的组件
  2. weightx属性设置为1.0

这是一个有效的演示代码(基于您的):

import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;

import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;

public class Gridbag {

    public void initUI() {
        JFrame frame = new JFrame();

        frame.setSize(500, 500);
        frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);

        JPanel p = new JPanel(new GridBagLayout());

        GridBagConstraints constraints = new GridBagConstraints();
        JButton button = new JButton("button 1");
        constraints.fill = GridBagConstraints.HORIZONTAL;
        constraints.anchor = GridBagConstraints.PAGE_START;
        constraints.gridwidth = GridBagConstraints.REMAINDER;
        constraints.weightx = 1.0;
        p.add(button, constraints);

        button = new JButton("button 2");
        constraints.fill = GridBagConstraints.HORIZONTAL;
        constraints.anchor = GridBagConstraints.PAGE_START;
        p.add(button, constraints);
        JPanel root = new JPanel(new GridBagLayout());
        constraints.weighty = 1.0;
        root.add(p, constraints);
        frame.add(root);
        frame.setVisible(true);
    }

    public static void main(String[] args) {
        SwingUtilities.invokeLater(new Runnable() {
            @Override
            public void run() {
                new Gridbag().initUI();
            }
        });
    }

}
于 2012-11-20T16:46:40.007 回答