ConveniencePatterns ConveniencePatterns - 4 months ago 17
Java Question

GridBagLayout stacks labels when using custom subclass from Jlabel

I am writing a GUI with Swing. I'm using a

GridBagLayout
to display multiple
JLabels
in a grid (basically like a chess board). 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
.

Either my subclass
TileLabel
is incorrect or I don't use the layout and constraints the right way. 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):

(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):

(MenuBar)
S


This is my simple subclass from 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. 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?

Answer

Override

You have accidentally overridden JComponent#getX() and 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). 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!)