With GroupLayout, how can I align separate components to each end of one longer component? Or, can one component span multiple parallel groups?

不问归期 提交于 2019-12-10 19:07:41

问题


tl;dr: I want to do what's in the second picture (ignore the red lines)

I understand how GroupLayout works, but I can't figure this out, or whether it's even possible. I initially had this code:

#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))))

which produced this:

However, I want to align the 2 top labels at the start and end of the progress bar, and the 3 bottom labels at the start, middle, and end of the progress bar, like this (mspainted):

My first approach at this was to try to split the components into the parallel groups I've made with the lines above. I put struts either side of the progress bar, aligning the 4 end labels to those, and aligned the center label to the progress bar itself:

#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))

However, as I expected, this forced the progress bar to squeeze into the horizontal space between the top 2 labels, like this:

Finally, I thought of getting rid of the struts, and adding the progress bar to three separate parallel groups: aligned LEADING with the two left labels, CENTER with the middle label, and TRAILING with the right label:

#Horizontal layout is a sequence of 4 parallel groups of components
layout.setHorizontalGroup(layout.createSequentialGroup()
                          .addGroup(layout.createParallelGroup(GroupLayout.Alignment.LEADING) #starttime, progleft, filesprog
                                    .addComponent(startTimeLabel)
                                    .addComponent(self.progressBar)
                                    .addComponent(self.fileProgLabel))
                          .addGroup(layout.createParallelGroup(GroupLayout.Alignment.CENTER) #progmid, sizeprog
                                    .addComponent(self.progressBar)
                                    .addComponent(self.sizeProgLabel))
                          .addGroup(layout.createParallelGroup(GroupLayout.Alignment.TRAILING) #updatetime, progright, ETC
                                    .addComponent(self.lastUpdatedLabel)
                                    .addComponent(self.progressBar)
                                    .addComponent(self.ETCLabel))
                          .addComponent(self.clearBtn))

However, Swing clearly ignores the second and third mentions of the progress bar, and I end up with this:

I reckon I've had a pretty decent go at this, and I'm well and truly out of ideas. Is there any way to make a component span multiple parallel groups?


回答1:


Given your requirements, I would rather use a GridBagLayout. It's a bit more complex but I wrote a piece of code that does what you want.

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

Here is the result:




回答2:


How would you nest it?

As shown below.

Seems like that would get overly-complicated pretty quickly.

It depends on the requirements.

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



回答3:


It's obviously too late, but I found this question while I was looking for something similar, so someone else might find this answer useful.

This answer actually uses GroupLayout. The only thing in here which I consider a hack is setting a preferred size to the scrollbar (if you take it out, the labels will overlap.)

It's simpler than you might have suspected:

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

There is probably a way to use a parallel group for the LEADING and TRAILING component pairs, but the layout completely rearranged when I tried to do that.

Sometimes the solution to GroupLayout problems is to ignore the vertical layout when doing the horizontal layout and ignore the horizontal layout when doing the vertical layout. Flatten the layout to a single dimension (rearranging similar rows and columns next to each other helps) and write the layout to match the 1D picture in your head.

I would particularly recommend against using GridBagLayout, boxes and the like, because getting the correct spacing between components in a cross-platform fashion is a nightmare.



来源:https://stackoverflow.com/questions/7279799/with-grouplayout-how-can-i-align-separate-components-to-each-end-of-one-longer

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!