GridLayout中的JLabel并不总是被绘制

时间:2014-12-04 12:49:18

标签: java swing jlabel paintcomponent repaint

我正在Java Swing中创建一个基本的Tic-Tac-Toe应用程序,为此,我开始研究绘图。但是,当JPanel的子类包含JLabel的子类的多个实例时,我遇到了一个问题,它以paintComponent(Graphic)数组格式覆盖了GridLayout方法嵌入自身。问题是只绘制了此数组中的第一个元素

JLabel的自定义子类的示例:

import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;

import javax.swing.JLabel;

@SuppressWarnings("serial")
public class DrawLabel extends JLabel {

    private boolean hasPaint;

    public DrawLabel() {
        super();
        this.hasPaint = false;
    }

    public void draw() {
        hasPaint = true;
        repaint();
    }

    public void clear() {
        hasPaint = false;
        repaint();
    }

    @Override
    public Dimension getPreferredSize() {
        return new Dimension(200, 200);
    }

    @Override
    protected void paintComponent(Graphics g) {
        super.paintComponent(g);

        Graphics2D g2 = (Graphics2D) g;

        if (hasPaint) {
            g2.drawOval(getX(), getY(), getWidth(), getHeight());
        } else {
            g2.clearRect(getX(), getY(), getWidth(), getHeight());
        }
    }
}

JPanel的自定义子类的示例:

import java.awt.Dimension;
import java.awt.GridLayout;

import javax.swing.JPanel;

@SuppressWarnings("serial")
public class DrawPanel extends JPanel {

    private Dimension size;
    private DrawLabel[][] fields;

    public DrawPanel(Dimension d) {
        super();
        this.size = d;
        this.fields = new DrawLabel[size.height][size.width];

        this.setLayout(new GridLayout(size.height, size.width));

        for (int i = 0; i < size.height; i++) {
            for (int j = 0; j < size.width; j++) {
                this.fields[i][j] = new DrawLabel();
                this.add(fields[i][j]);
            }
        }
    }

    public void draw(int row, int col) {
        fields[row][col].draw();
    }

    public void clear() {
        for (int i = 0; i < size.height; i++) {
            for (int j = 0; j < size.width; j++) {
                fields[i][j].clear();
            }
        }
    }
}

一个引发问题的场景的例子:

import java.awt.BorderLayout;
import java.awt.Dimension;

import javax.swing.JFrame;

public class Driver {

    public static void main(String[] args) {
        DrawPanel board = new DrawPanel(new Dimension(2, 1));

        JFrame canvas = new JFrame();
        canvas.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        canvas.add(board, BorderLayout.CENTER);
        canvas.pack();

        canvas.setLocationRelativeTo(null);
        canvas.setVisible(true);

        board.draw(0, 0); // This gets painted.
        board.draw(0, 1); // This does not get painted!
    }

}

奇怪的是,如果更改DrawPanel.draw(int, int)以设置元素的文本而不是绘制它,则只更新第二个元素,而第一个元素不更新,这与原始问题完全相反。

我试图查找与子组件绘制相关的其他问题和问题,但我还没有找到像这样的问题,似乎GridLayout中第一个以外的每个实例都不可绘制以同样的方式。可能有什么不对?

感谢您的时间和精力!

1 个答案:

答案 0 :(得分:4)

g2.drawOval(getX(), getY(), getWidth(), getHeight());

组件的绘制是相对于组件进行的,而不是绘制组件的面板.getX / Y()方法返回组件相对于父组件的位置。

因此,如果每个组件的大小为(200,200),则第一个组件的椭圆将使用

绘制
g2.drawOval(0, 0, 200, 200);

第二部分将在以下位置绘制:

g2.drawOval(200, 0, 200, 200);

但由于该组件的宽度仅为200像素,因此200的起始x位置超出了组件的范围,因此无需绘制任何内容。

而只是使用:

g2.drawOval(0, 0, getWidth(), getHeight());