Приведение менеджеров компоновки Java в соответствие с JTextFields и JLabels

У меня возникли небольшие проблемы с поведением менеджеров компоновки Java Swing. Я впервые пытаюсь создать собственный графический интерфейс, поэтому, вероятно, я просто пропустил что-то довольно простое, однако я был бы признателен за любые советы, которые можно предложить.

Я пытаюсь создать пользовательскую панель JPanel, которая содержит JLabels и JTextFields, чтобы позволить пользователю вводить IP-адрес (так что четыре JTextFields разделены между собой тремя JLabels, содержащими '.')

Мне очень сложно найти менеджера компоновки, который настроит это так, как я хотел бы; Я пробовал макет Flow и Box, и поскольку ни один из них не работал, я также попробовал GridBag, который, как мне показалось, был излишним, но даже он не работает правильно.

Вот мой код, который запускает класс:

public class PingPanel extends JPanel {
    private JLabel[] dotLabels;
    private JTextField[] pingFields;

    public PingPanel() {
        Dimension dim = getPreferredSize();
        dim.width = 400;
        setPreferredSize(dim);

        dotLabels = new JLabel[3];
        for (int i = 0; i < dotLabels.length; i++) {
            dotLabels[i] = new JLabel(".");
        }

        pingFields = new JTextField[4];
        for (int i = 0; i < pingFields.length; i++) {
            pingFields[i] = new JTextField(3);
        }

        Border panelBorder = BorderFactory.createLineBorder(Color.BLACK);
        setBorder(panelBorder);

        //setupFlow();
        //setupBox();
        //setupGridBag();

Я установил ширину панели только на 400, чтобы попытаться отобразить все (как вы вскоре увидите, мне с этим тоже не везет). Я понимаю, что некоторые менеджеры все равно игнорируют предпочтительные размеры, вероятно, поэтому это не работает. Я создал три метода, чтобы попробовать разные менеджеры компоновки; вот они с эффектом, который они производят:

public void setupFlow() {
    for (int p = 0; p < pingFields.length; p++) {
        if (p == dotLabels.length) {
            add(pingFields[p]);
            System.out.println(p + " (Final Column)");
        }

        else {
            add(pingFields[p]);
            add(dotLabels[p]);
            System.out.println(p);
        }
    }
}

FlowLayout производит это:

FlowLayout

Это наиболее близко к тому, как я хочу, чтобы это выглядело, но я не уверен, почему я получаю только одно JTextField и одну метку.

public void setupBox() {
    Container pingBox = Box.createHorizontalBox();

    for (int p = 0; p < pingFields.length; p++) {
        if (p == dotLabels.length) {
            pingBox.add(pingFields[p]);
            System.out.println(p + " (Final Column)");
        }

        else {
            pingBox.add(pingFields[p]);
            pingBox.add(dotLabels[p]);
            System.out.println(p);
        }
    }
}

Макет коробки

Это то, что дает мне BoxLayout. Я буквально понятия не имею, как я так сильно все испортил!

public void setupGridBag() {
    setLayout(new GridBagLayout());
    GridBagConstraints gc = new GridBagConstraints();

    gc.gridy = 0;
    gc.gridx = 0;
    gc.weightx = 1.0;
    gc.weighty = 1.0;
    gc.fill = GridBagConstraints.HORIZONTAL;

    add(pingFields[0], gc);

    gc.gridx++;
    add(dotLabels[0], gc);

    gc.gridx++;
    add(pingFields[1], gc);

    gc.gridx++;
    add(dotLabels[1], gc);

    gc.gridx++;
    add(pingFields[2], gc);

    gc.gridx++;
    add(dotLabels[2], gc);

    gc.gridx++;
    add(pingFields[3], gc);
}

GridBag

GridBagLayout, по крайней мере, дает мне макет, который я ищу, но я не смог понять, как сделать JTextFields шире.

Итак, мы здесь - я уверен, что моя зелень только что заставила меня пропустить что-то очевидное, но я был бы очень признателен, если бы у кого-нибудь были какие-либо идеи.


person lordchancellor    schedule 04.02.2015    source источник
comment
вы можете установить для параметра MinimumSize ширину по умолчанию, но это тоже не лучший способ.   -  person SomeJavaGuy    schedule 04.02.2015
comment
1) Чтобы быстрее получить помощь, опубликуйте MCVE (минимальный полный проверяемый пример) или SSCCE (краткий, автономный, правильный пример). 2) Предоставьте ASCII-графику или простой рисунок макета графического интерфейса в минимальном размере и, если размер можно изменить, с большей шириной и высотой.   -  person Andrew Thompson    schedule 04.02.2015
comment
Прошу прощения, я не понял, что не предоставил достаточно информации.   -  person lordchancellor    schedule 04.02.2015
comment
Мне удалось решить проблему — по-видимому, удаление кода для setPreferredSize заставило как FlowLayout, так и GridBagLayout работать должным образом. BoxLayout по-прежнему выглядит ужасно, но сейчас об этом не стоит беспокоиться.   -  person lordchancellor    schedule 04.02.2015


Ответы (1)


Обычно GridBagLayout это то, что вам нужно. Думайте об этом как о макете на основе сетки с пользовательским выравниванием для каждого компонента; также каждый компонент может занимать несколько столбцов и строк, что позволяет выполнять индивидуальную настройку.

У меня есть небольшой пример кода, как показано ниже:

    GridBagLayout gridBagLayout = new GridBagLayout();
    gridBagLayout.columnWidths = new int[] {30, 30, 60, 60, 60, 30, 30};
    gridBagLayout.rowHeights = new int[] {18, 18, 18, 18, 18, 18, 18, 18, 18};
    gridBagLayout.columnWeights = new double[] {0.1, 0.1, 0.2, 0.2, 0.2, 0.1, 0.1};
    gridBagLayout.rowWeights = new double[] {0.125, 0.125, 0.1, 0.1, 0.1, 0.1, 0.1, 0.125, 0.125};
    setLayout(gridBagLayout);

    JLabel labelLong = new JLabel("Long");
    labelLong.setForeground(Color.DARK_GRAY);
    labelLong.setFont(DisplayConstants.FONT_PANEL_LABEL_BOLD);
    GridBagConstraints gbc_labelLong = new GridBagConstraints();
    gbc_labelLong.insets = new Insets(0, 0, 5, 5);
    gbc_labelLong.gridx = 0;
    gbc_labelLong.gridy = 0;
    add(labelLong, gbc_labelLong);

    JLabel labelShort = new JLabel("Short");
    labelShort.setForeground(Color.DARK_GRAY);
    labelShort.setFont(DisplayConstants.FONT_PANEL_LABEL_BOLD);
    GridBagConstraints gbc_labelShort = new GridBagConstraints();
    gbc_labelShort.insets = new Insets(0, 0, 5, 0);
    gbc_labelShort.gridx = 6;
    gbc_labelShort.gridy = 0;
    add(labelShort, gbc_labelShort);

Если вам нужен простой макет, то вам подойдет BorderLayout. Поместите компонент фиксированного размера сбоку, а основной компонент — в центре.

Кроме того, стоит упомянуть, что Java использует setPreferredSize() для каждого компонента, чтобы указать дополнительные параметры размера, поэтому макет графического интерфейса будет стараться изо всех сил, чтобы удовлетворить предпочтительный размер для каждого компонента. Позвоните JFrame.pack() после того, как ваша конструкция будет закончена, чтобы также расположить компоненты.

person Alex Suo    schedule 04.02.2015
comment
Прав ли я, думая, что BorderLayout не подойдет для моей PingPanel, поскольку я пытаюсь выстроить семь компонентов в ряд? - person lordchancellor; 04.02.2015
comment
@lordchancellor Верно. GridBagLayout для этого. Вы можете создать действительно сложный пользовательский макет с ним. - person Alex Suo; 04.02.2015