使用GroupLayout,如何将单独的组件与一个较长组件的每一端对齐?或者,一个组件可以跨多个并行组吗?

时间:2011-09-02 06:10:41

标签: java swing user-interface grouplayout

tl;博士:我想做第二张图片中的内容(忽略红线)

我理解GroupLayout是如何工作的,但我无法弄清楚这一点,或者它是否可能。我最初有这个代码:

#Horizontal layout is a parallel group containing 3 sequences of components
layout.setHorizontalGroup(layout.createParallelGroup(GroupLayout.Alignment.LEADING) #everything else to the right
                          .addGroup(layout.createSequentialGroup() #row 1
                                    .addComponent(startTimeLabel)
                                    .addComponent(self.lastUpdatedLabel))
                          .addGroup(layout.createSequentialGroup() #row 2
                                    .addComponent(self.progressBar)
                                    .addComponent(self.clearBtn))
                          .addGroup(layout.createSequentialGroup() #row 3
                                    .addComponent(self.fileProgLabel)
                                    .addComponent(self.sizeProgLabel)
                                    .addComponent(self.ETCLabel))))

产生了这个: enter image description here

但是,我想在进度条的开头和结尾对齐2个顶部标签,在进度条的开始,中间和结尾对齐3个底部标签,如下所示(mspainted): enter image description here

我的第一个方法是尝试将组件拆分为我用上面的线组成的并行组。我在进度条的两侧放置了支柱,将4个末端标签对齐,并将中心标签与进度条本身对齐:

#Horizontal layout is a sequence of 3 parallel groups of components, and an end component
layout.setHorizontalGroup(layout.createSequentialGroup()
                          .addGroup(layout.createParallelGroup(GroupLayout.Alignment.LEADING) #starttime, strut, filesprog
                                    .addComponent(startTimeLabel)
                                    .addComponent(progLeft) #invisible, just for gluing things to
                                    .addComponent(self.fileProgLabel))
                          .addGroup(layout.createParallelGroup(GroupLayout.Alignment.CENTER) #progress bar, sizeprog
                                    .addComponent(self.progressBar)
                                    .addComponent(self.sizeProgLabel))
                          .addGroup(layout.createParallelGroup(GroupLayout.Alignment.TRAILING) #updatetime, strut, ETC
                                    .addComponent(self.lastUpdatedLabel)
                                    .addComponent(progRight) #invisible, just for gluing things to
                                    .addComponent(self.ETCLabel))
                          .addComponent(self.clearBtn))

然而,正如我所料,这迫使进度条挤入前2个标签之间的水平空间,如下所示: enter image description here

最后,我想要摆脱struts,并将进度条添加到三个单独的并行组中:将LEADING与两个左侧标签对齐,CENTER与中间标签对齐,{{{ 1}}使用正确的标签:

TRAILING

然而,Swing明显忽略了进度条的第二和第三次提及,我最终得到了这个: enter image description here

我认为我在这方面做得非常不错,而且我很有想法。有没有办法让组件跨越多个并行组?

3 个答案:

答案 0 :(得分:3)

根据您的要求,我宁愿使用GridBagLayout。它有点复杂,但我写了一段代码,可以做你想要的。

class T extends JFrame {

public T() {
    setDefaultCloseOperation(EXIT_ON_CLOSE);

    String s1 = "Started at: 2011-09-12 15:33:38";
    String s2 = "Last updated: 2011-09-12 15:33:44";
    String s3 = "File copied:2/10";
    String s4 = "Bytes copied: 234/1000";
    String s5 = "ETC: 2011-09-02 15:34:02";
    JProgressBar progressBar = new JProgressBar();

    progressBar.setMinimum(100);
    progressBar.setStringPainted(true);
    progressBar.setString("23%");
    progressBar.setValue(23);

    setLayout(new GridBagLayout());

    GridBagConstraints c = new GridBagConstraints();

    c.fill = GridBagConstraints.HORIZONTAL;
    c.weightx = 1.0;
    c.insets = new Insets(5, 5, 5, 5);
    add(new JLabel(s1), c);

    c.gridx = 2;
    add(new JLabel(s2, JLabel.RIGHT), c);

    c.gridx = 0;
    c.gridy = 1;
    c.gridwidth = 3;
    add(progressBar, c);

    c.gridx = 3;
    add(new JButton("Clear"), c);

    c.gridx = 0;
    c.gridy = 2;
    add(new JLabel(s3), c);

    c.gridx = 0;
    add(new JLabel(s4, JLabel.CENTER), c);

    c.gridx = 2;
    add(new JLabel(s5, JLabel.RIGHT), c);

    setSize(600, 300);
    setVisible(true);

}

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

结果如下: screenshot

答案 1 :(得分:3)

  

你会如何筑巢?

如下图所示。

  

似乎很快就会变得过于复杂。

这取决于要求。

enter image description here

import java.awt.EventQueue;
import java.awt.GridLayout;
import javax.swing.Box;
import javax.swing.BoxLayout;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JProgressBar;

/** @see http://stackoverflow.com/questions/7279799 */
public class NestedLayout extends Box {

    private String s1 = "Started at: 2011-09-12 15:33:38";
    private String s2 = "Last updated: 2011-09-12 15:33:44";
    private String s3 = "File copied:2/10";
    private String s4 = "Bytes copied: 234/1000";
    private String s5 = "ETC: 2011-09-02 15:34:02";
    private JProgressBar pb = new JProgressBar();

    public NestedLayout(int axis) {
        super(axis);
        JPanel top = new JPanel(new GridLayout());
        top.add(new JLabel(s1, JLabel.LEFT));
        top.add(new JLabel(s2, JLabel.RIGHT));

        JPanel mid = new JPanel(new GridLayout());
        pb.setMaximum(100);
        pb.setStringPainted(true);
        pb.setString("23%");
        pb.setValue(23);
        mid.add(pb);

        JPanel bot = new JPanel(new GridLayout());
        bot.add(new JLabel(s3, JLabel.LEFT));
        bot.add(new JLabel(s4, JLabel.CENTER));
        bot.add(new JLabel(s5, JLabel.RIGHT));

        Box east = new Box(BoxLayout.Y_AXIS);
        east.add(Box.createVerticalGlue());
        east.add(new JButton("Clear"));
        east.add(Box.createVerticalGlue());

        JPanel center = new JPanel(new GridLayout(0, 1));
        center.add(top);
        center.add(mid);
        center.add(bot);

        this.add(center);
        this.add(east);
    }

    private void display() {
        JFrame f = new JFrame("NestedLayout");
        f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        f.add(this);
        f.pack();
        f.setLocationRelativeTo(null);
        f.setVisible(true);
    }

    public static void main(String[] args) {
        EventQueue.invokeLater(new Runnable() {

            @Override
            public void run() {
                new NestedLayout(BoxLayout.X_AXIS).display();
            }
        });
    }
}

答案 2 :(得分:2)

显然已经太晚了,但是当我寻找类似的东西时,我发现了这个问题,所以其他人可能会觉得这个答案很有用。

这个答案实际上使用了GroupLayout。这里我唯一认为是黑客攻击的是设置滚动条的首选大小(如果你把它拿出来,标签会重叠。)

它比您可能怀疑的更简单:

import javax.swing.DefaultBoundedRangeModel;
import javax.swing.GroupLayout;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JProgressBar;
import javax.swing.SwingUtilities;
import javax.swing.WindowConstants;

public class LayoutTest implements Runnable {
    private JLabel startTimeLabel = new JLabel("start time");
    private JLabel lastUpdatedLabel = new JLabel("last updated");
    private JLabel fileProgLabel = new JLabel("file progress");
    private JLabel sizeProgLabel = new JLabel("size progress");
    private JLabel etcLabel = new JLabel("etc");
    private JButton clearBtn = new JButton("Clear");
    private JProgressBar progressBar = new JProgressBar(new DefaultBoundedRangeModel(27, 0, 0, 100));

    public static void main(String[] args) {
        SwingUtilities.invokeLater(new LayoutTest());
    }

    @Override
    public void run() {
        progressBar.setStringPainted(true);

        JPanel panel = new JPanel();
        GroupLayout layout = new GroupLayout(panel);
        layout.setAutoCreateContainerGaps(true);
        layout.setAutoCreateGaps(true);
        panel.setLayout(layout);

        layout.setHorizontalGroup(layout.createSequentialGroup()
                .addGroup(layout.createParallelGroup(GroupLayout.Alignment.LEADING)
                        .addComponent(progressBar, GroupLayout.DEFAULT_SIZE, 500, GroupLayout.DEFAULT_SIZE)
                        .addComponent(startTimeLabel, GroupLayout.Alignment.LEADING)
                        .addComponent(fileProgLabel, GroupLayout.Alignment.LEADING)
                        .addComponent(sizeProgLabel, GroupLayout.Alignment.CENTER)
                        .addComponent(lastUpdatedLabel, GroupLayout.Alignment.TRAILING)
                        .addComponent(etcLabel, GroupLayout.Alignment.TRAILING))
                .addComponent(clearBtn));

        layout.setVerticalGroup(layout.createSequentialGroup()
                .addGroup(layout.createParallelGroup(GroupLayout.Alignment.BASELINE)
                        .addComponent(startTimeLabel)
                        .addComponent(lastUpdatedLabel))
                .addGroup(layout.createParallelGroup(GroupLayout.Alignment.BASELINE)
                        .addComponent(progressBar)
                        .addComponent(clearBtn))
                .addGroup(layout.createParallelGroup(GroupLayout.Alignment.BASELINE)
                        .addComponent(fileProgLabel)
                        .addComponent(sizeProgLabel)
                        .addComponent(etcLabel)));

        JFrame frame = new JFrame("Layout Test");
        frame.setContentPane(panel);
        frame.pack();
        frame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
        frame.setVisible(true);
    }
}

可能有一种方法可以为LEADING和TRAILING组件对使用并行组,但是当我尝试这样做时,布局完全重新排列。

有时GroupLayout问题的解决方案是在执行水平布局时忽略垂直布局,在执行垂直布局时忽略水平布局。将布局展平为单个维度(重新排列彼此相邻的相似行和列有助于)并编写布局以匹配头部中的1D图片。

我特别建议不要使用GridBagLayout,方框等,因为以跨平台的方式在组件之间获得正确的间距是一场噩梦。