如何布置组件以使中间组件获得所有空间,但最右边的组件是否对齐?

时间:2013-07-09 00:45:04

标签: java swing layout-manager

我有一个由按钮(X),标签(Y)和进度条(Z)组成的面板。理想情况下,我想这样做:

| X-X Y---------------Y Z---Z ============= |  <-- expanded-size panel
                              ^ extra space

| X-X Y------Y Z---Z |                         <-- reduced-size panel

上图显示:

  • 当面板展开时,额外的空间应该转到标签(Y),以便标签可以完全显示其文字。
  • 进度条(Z)应始终保留在标签(Y)旁边。
  • 当面板缩小时,标签(Y)的尺寸应减小。
  • 按钮(X)和进度条(Z)的大小应该是常量,不是标签(Y)的大小。

但是,当我尝试使用GroupLayout时,这就是扩展面板时会发生的情况:

| X-X Y---------------Y ============= Z---Z |  <-- expanded-size panel (bad)

问题是,当面板有额外的空间时,标签(Y)会扩展到超出需要的范围,这会将进度条(Z)推向右侧。我希望进度条的(Z)位置在标签(Y)旁边。

如何完成此布局?

示例代码(“Blah.java”):

import java.awt.*;
import javax.swing.*;

public class Blah extends JPanel {
    public Blah() {
        final JButton X = new JButton("X");
        final JLabel Y = new JLabel("yyyyyyyyyyy");
        Y.setOpaque(true);
        Y.setBackground(Color.YELLOW);
        final JProgressBar Z = new JProgressBar();
        Z.setIndeterminate(true);

        final GroupLayout l = new GroupLayout(this);
        super.setLayout(l);

        l.setHorizontalGroup(
                l.createSequentialGroup()
                .addComponent(X, GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE)
                .addComponent(Y, 0, GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
                .addComponent(Z, GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE));

        l.setVerticalGroup(
                l.createParallelGroup()
                .addComponent(X)
                .addComponent(Y)
                .addComponent(Z));
    }

    public static void main(String[] args) {
        SwingUtilities.invokeLater(new Runnable() {
            public void run() {
                final JFrame frame = new JFrame("Blah");
                frame.add(new Blah());
                frame.pack();
                frame.setVisible(true);
            }
        });
    }
}

2 个答案:

答案 0 :(得分:4)

一个单独的布局管理器很少能满足您的所有需求。相反,您可以使用复合布局方法。

也就是说,将每个单独的布局要求分成一个单独的组件,并使用它自己的布局管理器。然后将所有这些添加到主组件中,管理总体要求。

作为一个例子

enter image description here enter image description here

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
import javax.swing.border.LineBorder;

public class SimpleGridBagLayout {

    public static void main(String[] args) {
        new SimpleGridBagLayout();
    }

    public SimpleGridBagLayout() {
        EventQueue.invokeLater(new Runnable() {
            @Override
            public void run() {
                try {
                    UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
                } catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
                }

                JFrame frame = new JFrame("Testing");
                frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
                frame.setLayout(new BorderLayout());
                frame.add(new TestPane());
                frame.pack();
                frame.setLocationRelativeTo(null);
                frame.setVisible(true);
            }
        });
    }

    public class TestPane extends JPanel {

        public TestPane() {

            setLayout(new GridBagLayout());

            GridBagConstraints gbc = new GridBagConstraints();
            gbc.gridx = 0;
            add(createLabel("XXX-XXX", Color.BLUE), gbc);

            JPanel panel = new JPanel();
            panel.add(createLabel("Y-Y", Color.RED));
            panel.add(createLabel("ZZZZZ---ZZZZZ", Color.GREEN), gbc);

            gbc.gridx++;
            gbc.weightx = 1;
            add(panel, gbc);

        }

        protected JLabel createLabel(String text, Color border) {

            JLabel label = new JLabel(text);
            label.setBorder(new LineBorder(border));
            return label;

        }

        @Override
        public Dimension getPreferredSize() {
            return new Dimension(200, 100);
        }
    }

}

这里有很多因素在起作用。当可用大小较小时,子组件的首选大小和最小大小将对某些布局管理器如何布局组件产生重大影响。

<强>更新

public TestPane() {

    setLayout(new GridBagLayout());

    GridBagConstraints gbc = new GridBagConstraints();
    gbc.gridx = 0;
    add(createLabel("XXX-XXX", Color.BLUE), gbc);

    JPanel panel = new JPanel(new GridBagLayout());
    gbc = new GridBagConstraints();
    gbc.gridx = 0;
    panel.add(createLabel("Y-Y", Color.RED), gbc);
    gbc.gridx = 1;
    panel.add(createLabel("ZZZZZ---ZZZZZ", Color.GREEN), gbc);

    gbc = new GridBagConstraints();
    gbc.gridx = 1;
    gbc.weightx = 1;
    add(panel, gbc);

}

<强>更新

现在进行“非缩小”进度条

public class TestPane extends JPanel {

    public TestPane() {

        setLayout(new GridBagLayout());

        GridBagConstraints gbc = new GridBagConstraints();
        gbc.gridx = 0;
        add(createLabel("XXX-XXX", Color.BLUE), gbc);

        JPanel panel = new JPanel(new GridBagLayout());
        gbc = new GridBagConstraints();
        gbc.gridx = 0;
        panel.add(createLabel("Y-Y", Color.RED), gbc);
        gbc.gridx = 1;
        MyProgressBar pb = new MyProgressBar();
        panel.add(pb, gbc);

        gbc = new GridBagConstraints();
        gbc.gridx = 1;
        gbc.weightx = 1;
        add(panel, gbc);

    }

    protected JLabel createLabel(String text, Color border) {

        JLabel label = new JLabel(text);
        label.setBorder(new LineBorder(border));
        return label;

    }

    @Override
    public Dimension getPreferredSize() {
        return new Dimension(200, 100);
    }
}

public class MyProgressBar extends JProgressBar {

    @Override
    public Dimension getPreferredSize() {
        Dimension ps = super.getPreferredSize();
        ps.width = 75;
        return ps;
    }

    @Override
    public Dimension getMinimumSize() {
        return getPreferredSize();
    }

}

答案 1 :(得分:0)

在我的头撞到墙上太久之后,我在SpringLayout的教程(http://docs.oracle.com/javase/tutorial/uiswing/layout/spring.html)中发现了这个小文档:

  

当组件的getMaximumSizegetPreferredSize方法返回相同的值时,SpringLayout会将此解释为意味着组件不应被拉伸。

因此,使用SpringLayout并手动设置YZ的最大尺寸,可以实现上述理想布局。这是代码:

import java.awt.*;
import java.awt.event.*;
import javax.swing.*;

public class Blah extends JPanel {
    public Blah() {
        final JButton X = new JButton("X");
        final JLabel Y = new JLabel("yyyyyyyyyyy");
        Y.setOpaque(true);
        Y.setBackground(Color.YELLOW);
        final JProgressBar Z = new JProgressBar();
        Z.setIndeterminate(true);

        final SpringLayout l = new SpringLayout();
        super.setLayout(l);

        super.add(X);
        super.add(Y);
        super.add(Z);

        Z.setMaximumSize(Z.getPreferredSize());

        l.putConstraint(SpringLayout.WEST, X, 10, SpringLayout.WEST, this);
        l.putConstraint(SpringLayout.WEST, Y, 10, SpringLayout.EAST, X);
        l.putConstraint(SpringLayout.WEST, Z, 10, SpringLayout.EAST, Y);
        l.putConstraint(SpringLayout.EAST, this, 10, SpringLayout.EAST, Z);

        l.putConstraint(SpringLayout.NORTH, X, 10, SpringLayout.NORTH, this);
        l.putConstraint(SpringLayout.NORTH, Y, 10, SpringLayout.NORTH, this);
        l.putConstraint(SpringLayout.NORTH, Z, 10, SpringLayout.NORTH, this);

    }

    public static void main(String[] args) {
        SwingUtilities.invokeLater(new Runnable() {
            public void run() {
                final JFrame frame = new JFrame("Blah");
                frame.add(new Blah());
                frame.pack();
                frame.setVisible(true);
            }
        });
    }
}