GridLayout 表现出奇怪的行为
GridLayout is showing odd behavior
我正在尝试创建一个由 100 个正方形组成的网格。我下面的代码非常错误,我不确定为什么。
import javax.swing.*;
import javax.swing.border.Border;
import java.awt.*;
public class snake extends JFrame
{
public static void main(String[] args)
{
Border whiteLine = BorderFactory.createLineBorder(Color.white);
//-----------FRAME
JFrame frame = new JFrame();
frame.setSize(1000,1000);
frame.setTitle("Snake");
frame.setDefaultCloseOperation(EXIT_ON_CLOSE);
frame.getContentPane().setBackground(Color.black);
frame.setVisible(true);
frame.setLayout(new GridLayout(10,10));
//-----------FRAME
//-----------PANELS
Dimension panelDimension = new Dimension(20,20);
int counter = 0;
JPanel[][] p = new JPanel[10][10];
for (int i = 0; i < 10; i++)
{
for (int j = 0; j < 10; j++)
{
p[i][j] = new JPanel();
//p[i][j].setPreferredSize(panelDimension);
p[i][j].setBackground(Color.red);
//p[i][j].setLocation(490,490);
p[i][j].setBorder(whiteLine);
p[i][j].setVisible(true);
frame.getContentPane().add(p[i][j]);
counter+=1;
}
}
System.out.println("counter: " + counter);
}
}
当我 运行 这样的代码时,它会显示一个由 2 列组成的网格,第一列有 7 行,第二列有 6 行。有时它甚至会显示其他不正确的列数和行数。我不确定为什么它不创建 10 行 10 列的网格。
您遇到了几个问题,包括:
- 在 JFrame 上调用
setVisible(true)
before 添加组件,然后在顶层调用 pack()
window。这可能导致我们的 GUI 中的不稳定定位组件甚至 GUI 仍然是空的
- 在添加组件之后和将其设置为可见之前不在 JFrame 上调用
pack()
- 正在设置 JFrame 的大小。让布局管理器、容器和组件为你做这件事(这就是调用
pack()
的目的)
- 将其设置为错误的大小,一个“完美的正方形”,忽略 OS 添加的菜单栏,
- ...
例如:
package foo01;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.GridLayout;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import javax.swing.*;
@SuppressWarnings("serial")
public class SnakePanel extends JPanel {
private static final int CELL_WIDTH = 80;
private static final Dimension CELL_DIMENSION = new Dimension(CELL_WIDTH, CELL_WIDTH);
private static final int COLUMNS = 10;
private static final int GAP = 2;
private static final Color BG_COLOR = Color.WHITE;
private static final Color CELL_COLOR = Color.RED;
public SnakePanel() {
setBackground(BG_COLOR);
// add a white line around the grid
setBorder(BorderFactory.createEmptyBorder(GAP, GAP, GAP, GAP));
// create a grid with gaps that show the background (white) color
setLayout(new GridLayout(COLUMNS, COLUMNS, GAP, GAP));
for (int row = 0; row < COLUMNS; row++) {
for (int col = 0; col < COLUMNS; col++) {
JPanel cell = new JPanel(); // create a new cell
cell.setPreferredSize(CELL_DIMENSION); // cheating here. Better to override getPreferredSize()
cell.setBackground(CELL_COLOR);
add(cell);
// give the cell JPanel some simple behavior:
cell.addMouseListener(new MyMouse(col, row));
}
}
}
private class MyMouse extends MouseAdapter {
private int col;
private int row;
public MyMouse(int col, int row) {
this.col = col;
this.row = row;
}
@Override
public void mousePressed(MouseEvent e) {
System.out.printf("Mouse pressed row and column: [%d, %d]%n", row, col);
}
}
public static void main(String[] args) {
SwingUtilities.invokeLater(() -> {
// create the main JPanel
SnakePanel snakePanel = new SnakePanel();
// create the JFrame
JFrame frame = new JFrame("Snake");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
// add the main JPanel to the JFrame
frame.add(snakePanel);
// pack the JFrame -- tells the layout managers to do their things
frame.pack();
// if we want to center the GUI:
frame.setLocationRelativeTo(null);
// only *now* do we display the GUI
frame.setVisible(true);
});
}
}
代码的一些注释:
传递给 SwingUtilities.invokeLater(...)
方法的 Runnable 中的任何代码都在 Swing 事件线程上调用,这在创建 Swing GUI 时是明智的做法
SwingUtilities.invokeLater(() -> {
// ....
});
首先,创建由 JFrame 持有的主 JPanel:
SnakePanel snakePanel = new SnakePanel();
然后创建 JFrame,添加 JPanel 并调用 pack()
。 pack 调用告诉布局管理器做这些事情,在容器中布置组件,根据它们的首选大小和布局调整大小:
JFrame frame = new JFrame("Snake");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(snakePanel);
frame.pack();
如果我们想让 GUI 居中:
frame.setLocationRelativeTo(null);
现在我们只显示 GUI
frame.setVisible(true);
我正在尝试创建一个由 100 个正方形组成的网格。我下面的代码非常错误,我不确定为什么。
import javax.swing.*;
import javax.swing.border.Border;
import java.awt.*;
public class snake extends JFrame
{
public static void main(String[] args)
{
Border whiteLine = BorderFactory.createLineBorder(Color.white);
//-----------FRAME
JFrame frame = new JFrame();
frame.setSize(1000,1000);
frame.setTitle("Snake");
frame.setDefaultCloseOperation(EXIT_ON_CLOSE);
frame.getContentPane().setBackground(Color.black);
frame.setVisible(true);
frame.setLayout(new GridLayout(10,10));
//-----------FRAME
//-----------PANELS
Dimension panelDimension = new Dimension(20,20);
int counter = 0;
JPanel[][] p = new JPanel[10][10];
for (int i = 0; i < 10; i++)
{
for (int j = 0; j < 10; j++)
{
p[i][j] = new JPanel();
//p[i][j].setPreferredSize(panelDimension);
p[i][j].setBackground(Color.red);
//p[i][j].setLocation(490,490);
p[i][j].setBorder(whiteLine);
p[i][j].setVisible(true);
frame.getContentPane().add(p[i][j]);
counter+=1;
}
}
System.out.println("counter: " + counter);
}
}
当我 运行 这样的代码时,它会显示一个由 2 列组成的网格,第一列有 7 行,第二列有 6 行。有时它甚至会显示其他不正确的列数和行数。我不确定为什么它不创建 10 行 10 列的网格。
您遇到了几个问题,包括:
- 在 JFrame 上调用
setVisible(true)
before 添加组件,然后在顶层调用pack()
window。这可能导致我们的 GUI 中的不稳定定位组件甚至 GUI 仍然是空的 - 在添加组件之后和将其设置为可见之前不在 JFrame 上调用
pack()
- 正在设置 JFrame 的大小。让布局管理器、容器和组件为你做这件事(这就是调用
pack()
的目的) - 将其设置为错误的大小,一个“完美的正方形”,忽略 OS 添加的菜单栏,
- ...
例如:
package foo01;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.GridLayout;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import javax.swing.*;
@SuppressWarnings("serial")
public class SnakePanel extends JPanel {
private static final int CELL_WIDTH = 80;
private static final Dimension CELL_DIMENSION = new Dimension(CELL_WIDTH, CELL_WIDTH);
private static final int COLUMNS = 10;
private static final int GAP = 2;
private static final Color BG_COLOR = Color.WHITE;
private static final Color CELL_COLOR = Color.RED;
public SnakePanel() {
setBackground(BG_COLOR);
// add a white line around the grid
setBorder(BorderFactory.createEmptyBorder(GAP, GAP, GAP, GAP));
// create a grid with gaps that show the background (white) color
setLayout(new GridLayout(COLUMNS, COLUMNS, GAP, GAP));
for (int row = 0; row < COLUMNS; row++) {
for (int col = 0; col < COLUMNS; col++) {
JPanel cell = new JPanel(); // create a new cell
cell.setPreferredSize(CELL_DIMENSION); // cheating here. Better to override getPreferredSize()
cell.setBackground(CELL_COLOR);
add(cell);
// give the cell JPanel some simple behavior:
cell.addMouseListener(new MyMouse(col, row));
}
}
}
private class MyMouse extends MouseAdapter {
private int col;
private int row;
public MyMouse(int col, int row) {
this.col = col;
this.row = row;
}
@Override
public void mousePressed(MouseEvent e) {
System.out.printf("Mouse pressed row and column: [%d, %d]%n", row, col);
}
}
public static void main(String[] args) {
SwingUtilities.invokeLater(() -> {
// create the main JPanel
SnakePanel snakePanel = new SnakePanel();
// create the JFrame
JFrame frame = new JFrame("Snake");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
// add the main JPanel to the JFrame
frame.add(snakePanel);
// pack the JFrame -- tells the layout managers to do their things
frame.pack();
// if we want to center the GUI:
frame.setLocationRelativeTo(null);
// only *now* do we display the GUI
frame.setVisible(true);
});
}
}
代码的一些注释:
传递给 SwingUtilities.invokeLater(...)
方法的 Runnable 中的任何代码都在 Swing 事件线程上调用,这在创建 Swing GUI 时是明智的做法
SwingUtilities.invokeLater(() -> {
// ....
});
首先,创建由 JFrame 持有的主 JPanel:
SnakePanel snakePanel = new SnakePanel();
然后创建 JFrame,添加 JPanel 并调用 pack()
。 pack 调用告诉布局管理器做这些事情,在容器中布置组件,根据它们的首选大小和布局调整大小:
JFrame frame = new JFrame("Snake");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(snakePanel);
frame.pack();
如果我们想让 GUI 居中:
frame.setLocationRelativeTo(null);
现在我们只显示 GUI
frame.setVisible(true);