【问题标题】:GridLayout is showing odd behaviorGridLayout 表现出奇怪的行为
【发布时间】:2021-12-29 17:13:25
【问题描述】:

我正在尝试创建一个由 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 列的网格。

【问题讨论】:

  • 1) 类名应以大写字符开头。 2)不要扩展JFrame,不需要扩展任何类。您的代码创建了一个 JFrame 实例,因此不需要两个实例。 3) Swing组件默认是可见的,所以不需要让面板可见。

标签: java swing jframe layout-manager grid-layout


【解决方案1】:

你有几个问题,包括:

  • 在JFrame添加组件之前调用setVisible(true),然后在顶层窗口调用pack()。这可能会导致我们的 GUI 中的定位组件不稳定,甚至 GUI 仍然为空
  • 在添加组件后和设置可见之前,不在 JFrame 上调用 pack()
  • 设置 JFrame 的大小。让布局管理器、容器和组件为您执行此操作(这就是调用 pack() 的目的)
  • 将其设置为错误的大小,即“完美正方形”,忽略操作系统添加的菜单栏,
  • ...

例如:

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);
        });
    }
}

关于代码的一些注释:

Runnable 中传递给SwingUtilities.invokeLater(...) 方法的任何代码都会在 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);

【讨论】:

  • 我认为将 frame.setVisible(true) 作为最后一段代码解决了我的问题。 Pack 还通过强制执行我的面板尺寸大小来帮助。但是对于您创建不同单元格的方法,是否无法从主要正确更改有关单个单元格的任何细节?
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-07-05
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多