【问题标题】:JLabels in GridLayout are Not Always PaintedGridLayout 中的 JLabel 并不总是绘制
【发布时间】:2014-12-04 12:49:17
【问题描述】:

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

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 中第一个以外的每个实例都无法在同样的方法。有什么问题?

感谢您的时间和精力!

【问题讨论】:

  • MarkLabel 缺少 repaint()
  • @mKorbel 绘画预计会发生在 MarkLabel.drawMark(Mark),其中还包含对 repaint() 的调用。
  • 为了尽快获得更好的帮助,请发布MCVE(最小完整可验证示例)或SSCCE(简短、自包含、正确示例)。
  • "..我以后一定会这样做的!"那么我必须确保我以后注意你的问题..当然,现在可以edit this question
  • @AndrewThompson 我的道歉。我在保持相同分隔的同时最小化了问题实例的显示范围。还有什么我可以做的吗?

标签: java swing jlabel paintcomponent repaint


【解决方案1】:
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());

【讨论】:

  • 解决了将getX()getY()替换为零的问题!我确实意识到这些方法返回了相对于其父组件的子组件原点,但是,我没有意识到绘画必须相对于子组件本身,而不是父组件。谢谢!
猜你喜欢
  • 2014-11-30
  • 1970-01-01
  • 2012-04-09
  • 1970-01-01
  • 2013-03-08
  • 1970-01-01
  • 2011-11-16
  • 1970-01-01
  • 2014-09-28
相关资源
最近更新 更多