#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:
Тот же результат может быть достигнут 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:
Ответ №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);