简体   繁体   English

GridBagLayout在使用Jlabel中的自定义子类时会堆叠标签

[英]GridBagLayout stacks labels when using custom subclass from Jlabel

I am writing a GUI with Swing. 我正在用Swing编写GUI。 I'm using a GridBagLayout to display multiple JLabels in a grid (basically like a chess board). 我正在使用GridBagLayout在网格中显示多个JLabels (基本上像棋盘一样)。 As soon as I use a self made label class derived from JLabel instead of JLabel , the GridBagLayout stacks every label on the top left corner of the JPanel . 一旦我使用从JLabel而不是JLabel派生的自制标签类, GridBagLayout所有标签堆叠在JPanel左上角。

Either my subclass TileLabel is incorrect or I don't use the layout and constraints the right way. 我的子类TileLabel不正确,或者我没有使用正确的布局和约束。 I think the last one because I can't see what would be a problem in such a minimal subclass. 我认为是最后一个,因为我看不到最小的子类会有什么问题。

This is how it looks using JLabel (L represents a label): 这是使用JLabel外观(L表示标签):

(MenuBar)
L L L L L L L L L
L L L L L L L L L
L L L L L L L L L

This is how it looks using TileLabel (S represents all the labels stacked): 使用TileLabel外观TileLabel (S代表堆叠的所有标签):

(MenuBar)
S 

This is my simple subclass from JLabel: 这是我来自JLabel的简单子类:

import javax.swing.JLabel;

public class TileLabel extends JLabel {
    private static final long serialVersionUID = 6718776819945522562L;
    private int x;
    private int y;

    public TileLabel(int x, int y) {
        super();
        this.x = x;
        this.y = y;
    }

    public int getX() {
        return x;
    }

    public int getY() {
        return y;
    }
}

And this is the GUI class. 这是GUI类。 I Marked the three lines where I used my custom label which lead to the layout problem. 我标记了三行使用自定义标签的行,这导致布局问题。

import java.awt.Color;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;

import javax.swing.JFrame;
import javax.swing.JPanel;

public class MainGUI extends JPanel {
    private static final long serialVersionUID = -8750891542665009043L;
    private JFrame frame;
    private MainMenuBar menuBar;
    private TileLabel[][] labelGrid; // <-- LINE 1
    private GridBagConstraints constraints;
    private int gridWidth;
    private int gridHeight;

     // Basic constructor.
    public MainGUI(int frameWidth, int frameHeight) {
        super(new GridBagLayout());
        constraints = new GridBagConstraints();
        buildFrame(frameWidth, frameHeight);
        buildLabelGrid(frameWidth, frameHeight);
    }

    // Builds the frame.
    private void buildFrame(int frameWidth, int frameHeight) {
        menuBar = new MainMenuBar();
        frame = new JFrame("Carcasonne");
        frame.getContentPane().add(this);
        frame.setJMenuBar(menuBar);
        frame.setResizable(false);
        frame.setVisible(true);
        frame.setSize(frameWidth, frameHeight);
        frame.setLocationRelativeTo(null);
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        setBackground(new Color(165, 200, 245));
    }

    // Creates the grid of labels.
    private void buildLabelGrid(int frameWidth, int frameHeight) {
        gridWidth = frameWidth / 100;
        gridHeight = frameHeight / 100;
        labelGrid = new TileLabel[gridWidth][gridHeight]; // <-- LINE 2
        for (int x = 0; x < gridWidth; x++) {
            for (int y = 0; y < gridHeight; y++) {
                labelGrid[x][y] = new TileLabel(x, y); // <-- LINE 3
                constraints.gridx = x;
                constraints.gridy = y;
                add(labelGrid[x][y], constraints); // add label with constraints
            }
        }
    }

    // sets the icon of a specific label
    public void paint(Tile tile, int x, int y) {
        if (x >= 0 && x < gridWidth && y >= 0 && y < gridHeight) {
            labelGrid[x][y].setIcon(tile.getImage());
        } else {
            throw new IllegalArgumentException("Invalid label grid position (" + x + ", " + y + ")");
        }
    }

    // Just to test this GUI:
    public static void main(String[] args) {
        MainGUI gui = new MainGUI(1280, 768);
        Tile tile = TileFactory.createTile(TileType.Road);
        for (int x = 0; x < 12; x++) {
            for (int y = 0; y < 7; y++) {
                gui.paint(tile, x, x);
            }
        }
    }
}

Where is the problem? 问题出在哪儿?

There are quite a few things to fix in your code, but your problem originates from 3 things: 您的代码中有很多要解决的问题,但是您的问题源自三件事:

  1. Your method definitions in your custom label: 您的自定义标签中的方法定义:

     public class TileLabel extends JLabel { // @Override !!!! public int getX() { return x; } // @Override !!!! public int getY() { return y; } } 

    You are overriding JComponent 's getX() and getY() , which are responsible for returning their coordinates. 您将重写JComponentgetX()getY() ,它们负责返回它们的坐标。 This messes up the layout completely. 这完全弄乱了布局。

    Be careful with your paint method, a method with the same name exists in a superclass, though you are saved in this case since the arguments are different. 请注意您的paint方法,在同一个类中存在一个具有相同名称的方法,尽管在这种情况下您会被保存,因为参数是不同的。

  2. You have a typo at your loop: gui.paint(tile, x, x) should be gui.paint(tile, x, y) . 您在循环中gui.paint(tile, x, x)错别字: gui.paint(tile, x, x)应该是gui.paint(tile, x, y)

  3. The order in which you call your methods is wrong. 您调用方法的顺序是错误的。 First, you create the frame and display it, then you change its contents by adding the panel with the labels to it, then you change the text in the labels. 首先,创建框架并显示它,然后通过添加带有标签的面板来更改其内容,然后更改标签中的文本。 You should do this the other way around. 您应该以其他方式执行此操作。

My recommendations: 我的建议:

  • Make your paint method be made a member of your TileLabel class. 使您的paint方法成为TileLabel类的成员。 It makes more sense. 这更有意义。
  • Set the icons during creation of the labels, unless they are not known. 除非不知道,否则在创建标签期间设置图标。 If you can't, you might need to recalculate the space requirements. 如果不能,则可能需要重新计算空间需求。
  • Never make your layout dependent on the size of the screen or its resolution. 切勿使布局取决于屏幕的大小或其分辨率。 It makes for a fragile GUI (as noted in the comments). 它导致脆弱的GUI(如注释中所述)。 Use pack() for the frame to calculate the correct size. 对框架使用pack()来计算正确的大小。

覆写

You have accidentally overridden JComponent#getX() and JComponent#getY() . 您不小心覆盖了JComponent#getX()JComponent#getY() The values returned by this method are not consistent with the values that the layout may set internally (via calls to setBounds or so). 此方法返回的值是与该布局可以内部设置(通过调用的值一致setBounds左右)。 This messes up the layout. 这弄乱了布局。

(Admittedly, I did not really check whether this is the reason, but it likely is, and it is a problem in general!) (诚​​然,我并没有真正检查这是否是原因,但很可能是这样,而且通常是个问题!)

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM