С GroupLayout, как я могу выровнять отдельные компоненты к каждому концу одного более длинного компонента? Или один компонент может охватывать несколько параллельных групп? - PullRequest
3 голосов
/ 02 сентября 2011

tl; dr: я хочу сделать то, что на втором рисунке (игнорировать красные линии)

Я понимаю, как работает 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))

Однако, как я и ожидал, это заставило индикатор выполнения втиснуться в горизонтальное пространство между двумя верхними метками, например так: enter image description here

Наконец, я подумал о том, чтобы избавиться от распорок и добавить индикатор выполнения к трем отдельным параллельным группам: выровненный LEADING с двумя левыми метками, CENTER с средней меткой и TRAILING с правой метка:

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

Однако Swing явно игнорирует второе и третье упоминания индикатора выполнения, и в итоге я получаю следующее: enter image description here

Полагаю, я неплохо справился с этим, и у меня все в порядке с идеями. Можно ли сделать так, чтобы компонент охватывал несколько параллельных групп?

Ответы [ 3 ]

3 голосов
/ 03 сентября 2011

Как бы вы это вложили?

Как показано ниже.

Похоже, это слишком усложнилось бы довольно быстро.

Зависит от требований.

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();
            }
        });
    }
}
3 голосов
/ 02 сентября 2011

Учитывая ваши требования, я бы предпочел использовать 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

2 голосов
/ 08 февраля 2014

Очевидно, что уже слишком поздно, но я нашел этот вопрос, когда искал что-то похожее, поэтому кто-то может найти этот ответ полезным.

Этот ответ на самом деле использует 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, коробки и тому подобное, потому что получение правильного расстояния между компонентами в кросс-платформенном режиме - это кошмар.

...