GridBagLayout привязка сетки не работает

#java #swing #layout #layout-manager #gridbaglayout

#java #качать #макет #макет-менеджер #gridbaglayout

Вопрос:

Я пытаюсь создать следующий графический интерфейс:

введите описание изображения здесь

но графический интерфейс, который я создаю, является:

введите описание изображения здесь

Как выглядит моя сетка:

изображение: СЕТОЧНОЕ ОПИСАНИЕ ДЛЯ ЭТОГО

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

Метод addComp add добавляет компонент ввода на панель ввода в заданном положении (x, y) и при заданной ширине и высоте компонента.

Код:

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

public class GUIError extends JFrame {

    //initialise all the components
    JPanel mainPanel = new JPanel();
    JTextField txtDisplay = new JTextField();
    JButton btnA = new JButton("A");
    JButton btnB = new JButton("B");
    JButton btnC = new JButton("C");
    JButton btnD = new JButton("D");
    JButton btnE = new JButton("E");
    JButton btnF = new JButton("F");
    JButton btnWA = new JButton("WA");
    JButton btnWB = new JButton("WB");
    JButton btnWC = new JButton("WC");
    JButton btnWD = new JButton("WD");

    private void addComp(JPanel panel, JComponent comp, int xPos, int yPos, int compWidth, int compHeight) {

        GridBagConstraints gridConstraints = new GridBagConstraints();

        gridConstraints.gridx = xPos;
        gridConstraints.gridy = yPos;
        gridConstraints.gridwidth = compWidth;
        gridConstraints.gridheight = compHeight;
        gridConstraints.weightx = 0.5;
        gridConstraints.weighty = 0.5;
        gridConstraints.insets = new Insets(5, 5, 5, 5);
        gridConstraints.anchor = GridBagConstraints.CENTER;
        gridConstraints.fill = GridBagConstraints.BOTH;

        panel.add(comp, gridConstraints);

    }


    public static void main(String[] args) {
        try {
            for (UIManager.LookAndFeelInfo info : UIManager.getInstalledLookAndFeels()) {
                if ("Nimbus".equals(info.getName())) {
                    UIManager.setLookAndFeel(info.getClassName());
                    break;
                }
            }
        }
        catch (Exception e) { }

        SwingUtilities.invokeLater(new Runnable() {

            public void run() {

                // create frame
                JFrame frame = new JFrame("Calculator");
                frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
                frame.setLocationRelativeTo(null);
                Container c = frame.getContentPane();

                // create GUI within frame              
                new GUIError(c);

                // finish frame definition
                frame.pack();
                frame.setResizable(false);
                frame.setVisible(true);

            }

        });
    }

    public GUIError(Container cont) {

        cont.setPreferredSize(new Dimension(610, 250));

        // parent panel containes every other panel
        mainPanel.setLayout(new GridBagLayout());

        // text display
        txtDisplay.setEditable(false);
        addComp(mainPanel, txtDisplay, 0, 0, 12, 2); // width 16, height 2


        addComp(mainPanel, btnA, 0, 2, 2, 1);
        addComp(mainPanel, btnB, 2, 2, 2, 1);
        addComp(mainPanel, btnC, 4, 2, 2, 1);
        addComp(mainPanel, btnD, 6, 2, 2, 1);
        addComp(mainPanel, btnE, 8, 2, 2, 1);
        addComp(mainPanel, btnF, 10, 2, 2, 1);
        addComp(mainPanel, btnWA, 0, 3, 3, 1);
        addComp(mainPanel, btnWB, 3, 3, 3, 1);
        addComp(mainPanel, btnWC, 6, 3, 3, 1);
        addComp(mainPanel, btnWD, 9, 3, 3, 1);

        cont.add(mainPanel);
    }
}
  

Комментарии:

1. GBC основаны на столбцах, 1 для вопроса и SSCCE / MCVE, причина, по которой разрабатывается MigLayout (например)

2. Не думайте, что вы можете достичь этого с помощью всего 1 панели. gridwidth насколько я знаю, невозможно указать «половину сетки». Я думаю, что лучшим выбором было бы либо использовать другой макет, либо разделить ваши компоненты на разные панели (главная панель содержит поле вверху и 2 панели внизу (рядом). бок о бок). каждая подпанель имеет 2 панели: одна для 3 кнопок меньшего размера, одна с 2 кнопками большего размера под ней)

3. Я не указал половину сетки, используя ширину сетки. Первая строка кнопок — gridwidth = 2, а третья строка кнопок — gridwidth = 3 . Я не понимаю, что вы подразумеваете под 3 меньшими и 2 большими кнопками внизу? Сетка, которую я также связал, отображает сетку, которую я использовал в этой ситуации. Второй ряд кнопок одинакового размера, третий ряд кнопок одинакового размера. Я не понимаю, почему это не будет работать с GridBagLayout.

4. @user3749872 Посмотрите на результаты, которые вы запрашиваете; вы хотите WA , чтобы и WB занимали столько же места, сколько и 3 другие кнопки. Как вы можете видеть по получаемым результатам, ваши компоненты, похоже, фиксируются на месте (выровнены со всем остальным). У вас есть 6 ячеек сетки из-за ваших маленьких кнопок; вы хотите WA занять 1 1/2 пространства сетки ниже и WB занять еще 1 1/2 (то же самое с WC и WD). В коде вы не пытались занять половину сетки, но результаты, которые вы запрашиваете, требуют этого. Это можно сделать, переключив макеты или разделив их панелями

5. Я опубликую ответ с объяснением вместе с решением. Дайте мне секунду

Ответ №1:

Этого можно легко достичь, используя GridBagLayout , как показано в этом примере, представленном ниже. Вам просто нужно взять два JPanel по одному для каждогоROW. Оба компонента используют GridBagLayout и добавляют компоненты в первую строку с weightx = 0,16, поскольку JButton предполагается, что каждый из них занимает такую большую площадь, а для второй строки weightx = 0,25, поскольку это площадь, занимаемая каждым JButton из них вдоль направления X

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

public class GridBagExample {
    private static final int SIZE = 10;
    private JButton[] buttons;
    private GridBagConstraints gbc;

    public GridBagExample() {
        buttons = new JButton[SIZE];
        gbc = new GridBagConstraints();
        gbc.insets = new Insets(5, 5, 5, 5);
    }

    private void createAndDisplayGUI() {
        JFrame frame = new JFrame("Grid Game");
        frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);

        JPanel contentPane = new JPanel();
        contentPane.setLayout(new GridLayout(2, 1, 5, 5));
        contentPane.setBorder(BorderFactory.createEmptyBorder(5, 5, 5, 5));

        JPanel topPanel = new JPanel();
        JTextField textField = new JTextField(10);
        //topPanel.add(textField);

        JPanel buttonPanel = new JPanel(new GridLayout(2, 1, 5, 5));
        JPanel headerPanel = new JPanel(new GridBagLayout());
        buttons[0] = new JButton("A");
        addComp(headerPanel, buttons[0], 0, 0, 0.16, 1.0, 1, 1, GridBagConstraints.BOTH);        
        buttons[1] = new JButton("B");
        addComp(headerPanel, buttons[1], 1, 0, 0.16, 1.0, 1, 1, GridBagConstraints.BOTH);
        buttons[2] = new JButton("C");
        addComp(headerPanel, buttons[2], 2, 0, 0.16, 1.0, 1, 1, GridBagConstraints.BOTH);
        buttons[3] = new JButton("D");
        addComp(headerPanel, buttons[3], 3, 0, 0.16, 1.0, 1, 1, GridBagConstraints.BOTH);
        buttons[4] = new JButton("E");
        addComp(headerPanel, buttons[4], 4, 0, 0.16, 1.0, 1, 1, GridBagConstraints.BOTH);
        buttons[5] = new JButton("F");
        addComp(headerPanel, buttons[5], 5, 0, 0.16, 1.0, 1, 1, GridBagConstraints.BOTH);

        JPanel footerPanel = new JPanel(new GridBagLayout());
        buttons[6] = new JButton("WA");
        addComp(footerPanel, buttons[6], 0, 0, 0.25, 1.0, 1, 1, GridBagConstraints.BOTH);
        buttons[7] = new JButton("WB");
        addComp(footerPanel, buttons[7], 1, 0, 0.25, 1.0, 1, 1, GridBagConstraints.BOTH);
        buttons[8] = new JButton("WC");
        addComp(footerPanel, buttons[8], 2, 0, 0.25, 1.0, 1, 1, GridBagConstraints.BOTH);
        buttons[9] = new JButton("WD");
        addComp(footerPanel, buttons[9], 3, 0, 0.25, 1.0, 1, 1, GridBagConstraints.BOTH);
        buttonPanel.add(headerPanel);
        buttonPanel.add(footerPanel);

        contentPane.add(textField);
        contentPane.add(buttonPanel);

        frame.setContentPane(contentPane);
        frame.pack();
        frame.setLocationByPlatform(true);
        frame.setVisible(true);
    }

    private void addComp(JPanel panel, JComponent comp, int x, int y,
                                    double wx, double wy, int gw, int gh, int fill) {
        gbc.gridx = x;
        gbc.gridy = y;
        gbc.weightx = wx;
        gbc.weighty = wy;
        gbc.gridwidth = gw;
        gbc.gridheight = gh;
        gbc.fill = fill;

        panel.add(comp, gbc);
    }

    public static void main(String... args) {
        SwingUtilities.invokeLater(new Runnable() {
            public void run() {
                new GridBagExample().createAndDisplayGUI();
            }
        });
    }
}
  

ВЫВОД:
GRIDBAGLAYOUT:

пример gridbagexample

Тот же результат может быть достигнут GridLayout , если GridBagLayout в этом случае нет необходимости, как указано в приведенном ниже примере:

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

public class GridBagExample {
    private static final int SIZE = 10;
    private JButton[] buttons;

    public GridBagExample() {
        buttons = new JButton[SIZE];
    }

    private void createAndDisplayGUI() {
        JFrame frame = new JFrame("Grid Game");
        frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);

        JPanel contentPane = new JPanel();
        contentPane.setLayout(new GridLayout(2, 1, 5, 5));
        contentPane.setBorder(BorderFactory.createEmptyBorder(5, 5, 5, 5));

        JPanel topPanel = new JPanel();
        JTextArea tArea = new JTextArea(5, 30);
        JScrollPane scroller = new JScrollPane();
        scroller.setViewportView(tArea);
        topPanel.add(scroller);

        JPanel buttonPanel = new JPanel(new GridLayout(2, 1, 5, 5));
        JPanel headerPanel = new JPanel(new GridLayout(1, 0, 5, 5));
        buttons[0] = new JButton("A");
        headerPanel.add(buttons[0]);
        buttons[1] = new JButton("B");
        headerPanel.add(buttons[1]);
        buttons[2] = new JButton("C");
        headerPanel.add(buttons[2]);
        buttons[3] = new JButton("D");
        headerPanel.add(buttons[3]);
        buttons[4] = new JButton("E");
        headerPanel.add(buttons[4]);
        buttons[5] = new JButton("F");
        headerPanel.add(buttons[5]);
        JPanel footerPanel = new JPanel(new GridLayout(1, 0, 5, 5));
        buttons[6] = new JButton("WA");
        footerPanel.add(buttons[6]);
        buttons[7] = new JButton("WB");
        footerPanel.add(buttons[7]);
        buttons[8] = new JButton("WC");
        footerPanel.add(buttons[8]);
        buttons[9] = new JButton("WD");
        footerPanel.add(buttons[9]);
        buttonPanel.add(headerPanel);
        buttonPanel.add(footerPanel);

        contentPane.add(topPanel);
        contentPane.add(buttonPanel);

        frame.setContentPane(contentPane);
        frame.pack();
        frame.setLocationByPlatform(true);
        frame.setVisible(true);
    }

    public static void main(String... args) {
        SwingUtilities.invokeLater(new Runnable() {
            public void run() {
                new GridBagExample().createAndDisplayGUI();
            }
        });
    }
}
  

ВЫВОД:
GRIDLAYOUT:
Пример GridBagExample

Ответ №2:

Обычно я бы делал отдельные панели, но эй, кому не нравится вызов?

Проблема в том, что некоторые столбцы не четко определены для GBL (нет единого компонента, определяющего его ширину), поэтому кнопка WA не знает, как далеко нужно зайти, чтобы покрыть половину кнопки B и т.д.

Итак, я добавил несколько разделителей нулевой ширины в столбцы, которые составляют необходимые разделы.

Все в одной панели:

введите описание изображения здесь

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

public class GridBagDemo3 implements Runnable
{
  private JPanel panel;

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

  public void run()
  {
    JTextArea text = new JTextArea(10,10);
    JButton btnA = new JButton("A");
    JButton btnB = new JButton("B");
    JButton btnC = new JButton("C");
    JButton btnD = new JButton("D");
    JButton btnE = new JButton("E");
    JButton btnF = new JButton("F");
    JButton btnWA = new JButton("WA");
    JButton btnWB = new JButton("WB");
    JButton btnWC = new JButton("WC");
    JButton btnWD = new JButton("WD");

    panel = new JPanel(new GridBagLayout());

    add(text,   0,0, 12,1);
    add(btnA,   0,1, 2,1);
    add(btnB,   2,1, 2,1);
    add(btnC,   4,1, 2,1);
    add(btnD,   6,1, 2,1);
    add(btnE,   8,1, 2,1);
    add(btnF,  10,1, 2,1);
    add(btnWA,  0,2, 3,1);
    add(btnWB,  3,2, 3,1);
    add(btnWC,  6,2, 3,1);
    add(btnWD,  9,2, 3,1);

    // SPACERS: define the 2 columns that button B spans
    //          so that WA and WB can split B, and same for button E
    add(null,   2,2, 1,1);
    add(null,   3,2, 1,1);
    add(null,   8,2, 1,1);
    add(null,   9,2, 1,1);

    JFrame frame = new JFrame("Grig Bag");
    frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    frame.getContentPane().add(panel);
    frame.pack();
    frame.setVisible(true);
  }

  private void add(Component comp, int x, int y, int colspan, int rowspan)
  {
    GridBagConstraints gbc = new GridBagConstraints();
    gbc.gridx = x;
    gbc.gridy = y;
    gbc.gridwidth = colspan;
    gbc.gridheight = rowspan;
    gbc.weighty = .1;
    gbc.anchor = GridBagConstraints.CENTER;
    gbc.fill = GridBagConstraints.BOTH;
    gbc.insets = new Insets(5,5,5,5);

    if (comp != null)
    {
      gbc.weightx = 1;
    }
    else
    {
      comp = Box.createHorizontalGlue();
      gbc.fill = GridBagConstraints.NONE;
      gbc.weightx = 0.1;
      gbc.weighty = 0;
    }

    panel.add(comp, gbc);
  }
}
  

Ответ №3:

@Matthieu написал —

не могли бы вы уточнить, основаны ли GBC на столбцах? Это звучит как объяснение проблемы, которую я заметил…

Я думаю, что таким образом разработан GridBagLayout, я всегда использую JLabels (без границ:-) в качестве матрицы…

введите описание изображения здесь

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

public class CopyTextNorthPanel extends JPanel {

    private static final long serialVersionUID = 1L;
    private JLabel hidelLabel;
    private JLabel firstLabel;
    private JTextField firstText;

    public CopyTextNorthPanel() {

        setLayout(new GridBagLayout());
        GridBagConstraints gbc = new GridBagConstraints();
        setComponentOrientation(ComponentOrientation.LEFT_TO_RIGHT);
        for (int k = 0; k < 50; k  ) {
            hidelLabel = new JLabel("     ");
            hidelLabel.setBorder(BorderFactory.createLineBorder(Color.BLACK, 1));
            gbc.fill = GridBagConstraints.HORIZONTAL;
            gbc.weightx = 0.5;
            gbc.weighty = 0.5;
            gbc.gridx = k;
            gbc.gridy = 0;
            add(hidelLabel, gbc);
        }
        for (int k = 0; k < 5; k  ) {
            firstLabel = new JLabel("Testing Label : ", SwingConstants.RIGHT);
            firstLabel.setFont(new Font("Serif", Font.BOLD, 20));
            firstLabel.setBorder(BorderFactory.createLineBorder(Color.BLACK, 1));
            gbc.fill = GridBagConstraints.HORIZONTAL;
            gbc.insets = new Insets(0, 0, 5, 0);
            gbc.gridx = 0;
            gbc.gridwidth = 8;
            gbc.gridy = k   1;
            add(firstLabel, gbc);
        }
        for (int k = 0; k < 5; k  ) {
            firstText = new JTextField("Testing TextField");
            firstText.setFont(new Font("Serif", Font.BOLD, 20));
            firstText.setBorder(BorderFactory.createLineBorder(Color.BLACK, 1));
            gbc.fill = GridBagConstraints.HORIZONTAL;
            gbc.insets = new Insets(0, 0, 5, 0);
            gbc.gridx = 9;
            gbc.gridwidth = k   8;
            gbc.gridy = k   1;
            add(firstText, gbc);
        }
        for (int k = 0; k < 5; k  ) {
            firstLabel = new JLabel("Testing Label : ", SwingConstants.RIGHT);
            firstLabel.setFont(new Font("Serif", Font.BOLD, 20));
            firstLabel.setBorder(BorderFactory.createLineBorder(Color.BLACK, 1));
            gbc.fill = GridBagConstraints.HORIZONTAL;
            gbc.insets = new Insets(0, 0, 5, 0);
            gbc.gridx = 20   k;
            gbc.gridwidth = 8;
            gbc.gridy = k   1;
            add(firstLabel, gbc);
        }
        for (int k = 0; k < 5; k  ) {
            firstText = new JTextField("Testing TextField");
            firstText.setFont(new Font("Serif", Font.BOLD, 20));
            firstText.setBorder(BorderFactory.createLineBorder(Color.BLACK, 1));
            gbc.fill = GridBagConstraints.HORIZONTAL;
            gbc.insets = new Insets(0, 0, 5, 0);
            gbc.gridx = 29   k;
            gbc.gridwidth = 21 - k;
            gbc.gridy = k   1;
            add(firstText, gbc);
        }
    }
}
  

Ответ №4:

если вам все еще интересно понять вашу ошибку: макет сетки не является FlowLayout, вы не можете просто добавить компонент, и он нарисует объект в тот же момент, когда программа его прочитает. В случае сетки виртуальная машина сначала считывает все объекты, а затем строит сетку, количество столбцов определяется в базе тех строк, в которых наибольшее количество столбцов. Итак, у вас была хорошая идея предпочесть 12 столбцов (таким образом, вы избегаете создания новой «панели» и запасных системных ресурсов), но чтобы сделать это правильно, вам просто нужно добавить 12 пустых пространств (не только пустых, но и с нулевым размером) в одну из строк

     // text display
    txtDisplay.setEditable(false);
    addComp(mainPanel, txtDisplay, 0, 0, 12, 2); // width 16, height 2



    //now go with empty spaces
    for(int i=0;i<12;i  ){
        GridBagConstraints gridConstraints = new GridBagConstraints();
        gridConstraints.gridx = i;    //12 times "i"
        gridConstraints.gridy = 1;  //you left y=1 empty, so why don't use it
        gridConstraints.gridwidth = 1;  //one column = one space in grid
        gridConstraints.gridheight = 0;  //we don't want it to occupied any space
        gridConstraints.weightx = 0.5;
        gridConstraints.weighty = 0.5;
        gridConstraints.insets = new Insets(0, 0, 0, 0); //same reason, we don't want it to occupied any space
        gridConstraints.anchor = GridBagConstraints.CENTER;
        gridConstraints.fill = GridBagConstraints.BOTH ;

        mainPanel.add(Box.createHorizontalGlue(), gridConstraints);
    }


    addComp(mainPanel, btnA, 0, 2, 2, 1);
    addComp(mainPanel, btnB, 2, 2, 2, 1);
    addComp(mainPanel, btnC, 4, 2, 2, 1);
    addComp(mainPanel, btnD, 6, 2, 2, 1);
    addComp(mainPanel, btnE, 8, 2, 2, 1);
    addComp(mainPanel, btnF, 10, 2, 2, 1);
    addComp(mainPanel, btnWA, 0, 3, 3, 1);
    addComp(mainPanel, btnWB, 3, 3, 3, 1);
    addComp(mainPanel, btnWC, 6, 3, 3, 1);
    addComp(mainPanel, btnWD, 9, 3, 3, 1);