When using null layout in Swing, my components don

2019-09-10 05:50发布

问题:

Recently I've been getting into making some simple games with Swing in Java. My current project is a chess-like game, so I figured I would start by making an 8 by 8 grid with JButtons and go from there.

The problem is that every time I run my app, half of the buttons are just missing, and they only appear when I hover above them. From what I've searched about this problem, most of the suggestions were saying that I shouldn't use null layout, and I should use some of the layouts already in Swing. But from what I've seen so far, Swing layouts are just a pain to work with (at least when compared to the Android ones), and I would prefer just using absolute positioning for now.

Also I've found that adding panel.repaint(); fixes the missing buttons, but I don't like that solution since it doesn't really fix the problem but more like it patches it. When running my app with repaint, I still see the missing buttons for a split second until they are repainted.

So what I am looking for is why this thing happens in the first place, and is there any way for it not to happen without using the bad Swing layouts.

import javax.swing.*;

public class Main {

    static final int TILE = 70;
    static final int WIDTH = 600;
    static final int HEIGHT = 600;

    public static void main(String[] args){
        JFrame frame = new JFrame("Knight's tour");
        frame.setSize(WIDTH, HEIGHT);
        frame.setResizable(false);
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.setLocationRelativeTo(null);
        frame.setVisible(true);

        JPanel panel = new JPanel();
        panel.setLayout(null);
        frame.add(panel);

        JButton[][] tiles = new JButton[8][8];

        for(int i = 0; i < 8; i++){
            for(int j = 0; j < 8; j++){
                tiles[i][j] = new JButton();
                tiles[i][j].setLocation(i*TILE, j*TILE);
                tiles[i][j].setSize(TILE, TILE);
                panel.add(tiles[i][j]);
            }
        }

        //panel.repaint(); //this thing fixes it, but I am looking for a better fix
    }
}

回答1:

Normally one would do last after adding the panel and its components:

frame.pack();
frame.setVisible(true);

The pack() doing some layouting on preferred sizes.

One could do a JTable 8x8 too.



回答2:

Avoid using null layouts for a number of reason. Different platform will treat them differently. They are difficult to maintain, among many other reasons. Instead use layout managers, and let them do the laying out and sizing of the components, as they were designed to do with Swing apps. Learn more at Laying out components Within a Container

For a chess game, it sounds like a GridLayout would be ideal for what you're looking for, without the same problems you're currently experiencing.



回答3:

First, you need to do the painting on the event thread. Second, you should make a class that extends JPanel, and if you really want to use a null layout, your panel should override paintComponent, and that method should first call super.paintComponent() and then position the child buttons appropriately.