Java paintComponent在调用repaint()之前不会绘制所有内容

Java paintComponent在调用repaint()之前不会绘制所有内容,java,swing,paintcomponent,Java,Swing,Paintcomponent,我正在使用一个国际象棋引擎,我有以下问题:除非调用repaint(),否则我的棋子不会被画出来。然而,方格(象棋场)看起来很好。 我读到我应该避免在paintComponent内部使用repaint(),因为这将使函数连续调用。如何避免调用repaint(),但仍然绘制图像? 代码如下: import java.awt.Color; import java.awt.Dimension; import java.awt.Frame; import java.awt.Graphics; import

我正在使用一个国际象棋引擎,我有以下问题:除非调用
repaint()
,否则我的棋子不会被画出来。然而,方格(象棋场)看起来很好。 我读到我应该避免在
paintComponent
内部使用
repaint()
,因为这将使函数连续调用。如何避免调用
repaint()
,但仍然绘制图像? 代码如下:

import java.awt.Color;
import java.awt.Dimension;
import java.awt.Frame;
import java.awt.Graphics;
import java.awt.Image;
import java.awt.Toolkit;
import java.util.ArrayList;

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

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

    ArrayList<Square> squares = new ArrayList<Square>();
    Piece piece = new Piece("B", 0);
    
    public ChessBoard() {
        for (int i = 0; i < 8; i++) {
            for (int j = 0; j < 8; j++) {
                squares.add(new Square(i, j));
            }
        }
    }
    
    @Override
    public void paintComponent(Graphics g) {
        super.paintComponent(g);
        for (Square square : squares) {
            square.draw(g);
        }
        piece.draw(g);
        //repaint(); //Image only appears if this is called
    }
    
    public static void main(String[] args) {
        // TODO Auto-generated method stub
        ChessBoard chessboard = new ChessBoard();
        chessboard.createFrame();
    }
    
    public void createFrame() {
        JFrame f = new JFrame("ChessBoard");
        f.getContentPane().setPreferredSize(new Dimension(squareSize()*8, squareSize()*8));
        f.setResizable(false);
        f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        f.setTitle("Chessboard");
        f.setLocation((int)(screenSize().width-squareSize()*8)/2, (int)(screenSize().height-squareSize()*8)/2);
        f.add(this);
        f.pack();
        Frame.getFrames();
        f.setVisible(true);
    }
    
    public static Dimension screenSize() {
        return Toolkit.getDefaultToolkit().getScreenSize();
    }
    
    public static int squareSize() {
        return (int)screenSize().height/12;
    }

}


class Square {
    int start_x, start_y;
    int square_size;
    Color color;
    
    public Square(int x, int y) {
        // constructor
        start_x = x*ChessBoard.squareSize();
        start_y = y*ChessBoard.squareSize();
        square_size = ChessBoard.squareSize();
        if ((x+y)%2 == 0) {
            // Color of the white squares
            color = new Color(209, 192, 148);
        } else {
            // Color of the black squares
            color = new Color(110, 83, 43);
        }
    }

    public void draw(Graphics g) {
        g.setColor(this.color);
        g.fillRect(this.start_x, this.start_y, square_size, square_size);
    }
}

class Piece {
    String type;
    int coordinate, square_size, piece_size;
    int[] draw_coordinates = {7, 6, 5, 4, 3, 2, 1, 0};
    Image image;
    
    public Piece(String type, int coordinate) {
        this.type = type;
        this.coordinate = coordinate;
        this.square_size = ChessBoard.squareSize();
        this.piece_size = (int)ChessBoard.squareSize()*2/3;
        this.image = Toolkit.getDefaultToolkit().getImage("src/pieces/black_bishop.png");
    }
    
    public int co_x_board() {
        return coordinate - ((int)coordinate/8)*8;
    }
    
    public int co_y_board() {
        return (int)coordinate/8;
    }
    
    public int co_x_draw() {
        return co_x_board()*square_size+((int)square_size/6);
    }
    
    public int co_y_draw() {
        return draw_coordinates[co_y_board()]*square_size+((int)square_size/6);
    }
    
    public void draw(Graphics g) {
        g.drawString(type, co_x_draw(), co_y_draw()); // does work
        g.drawImage(image, co_x_draw(), co_y_draw(), piece_size, piece_size, null); // does not work
    }
}
导入java.awt.Color;
导入java.awt.Dimension;
导入java.awt.Frame;
导入java.awt.Graphics;
导入java.awt.Image;
导入java.awt.Toolkit;
导入java.util.ArrayList;
导入javax.swing.JFrame;
导入javax.swing.JPanel;
@抑制警告(“串行”)
公共类棋盘扩展JPanel{
ArrayList squares=新的ArrayList();
工件=新工件(“B”,0);
公共棋盘(){
对于(int i=0;i<8;i++){
对于(int j=0;j<8;j++){
增加(新的平方(i,j));
}
}
}
@凌驾
公共组件(图形g){
超级组件(g);
用于(正方形:正方形){
方形图(g);
}
图(g);
//repaint();//图像仅在调用此函数时显示
}
公共静态void main(字符串[]args){
//TODO自动生成的方法存根
棋盘棋盘=新棋盘();
chessboard.createFrame();
}
public void createFrame(){
JFrame f=新的JFrame(“棋盘”);
f、 getContentPane().setPreferredSize(新维度(squareSize()*8,squareSize()*8));
f、 可设置大小(假);
f、 setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f、 设定标题(“棋盘”);
f、 设置位置((int)(屏幕大小().width-squareSize()*8)/2,(int)(屏幕大小().height-squareSize()*8)/2);
f、 加上(这个);
f、 包装();
Frame.getFrames();
f、 setVisible(真);
}
公共静态维度屏幕大小(){
返回Toolkit.getDefaultToolkit().getScreenSize();
}
公共静态int squareSize(){
返回(int)屏幕大小().高度/12;
}
}
阶级广场{
int start_x,start_y;
整数平方米;
颜色;
公共广场(内x,内y){
//建造师
start_x=x*棋盘.squareSize();
start_y=y*棋盘.squareSize();
square_size=棋盘。squareSize();
如果((x+y)%2==0){
//白色方块的颜色
颜色=新颜色(209192148);
}否则{
//黑色方块的颜色
颜色=新颜色(110,83,43);
}
}
公共空间绘制(图g){
g、 setColor(this.color);
g、 fillRect(this.start_x,this.start_y,square_size,square_size);
}
}
班级作品{
字符串类型;
整数坐标、正方形尺寸、工件尺寸;
int[]绘制坐标={7,6,5,4,3,2,1,0};
图像;
公共件(字符串类型,整数坐标){
this.type=type;
这个坐标=坐标;
this.square_size=ChessBoard.squareSize();
this.piece_size=(int)ChessBoard.squareSize()*2/3;
this.image=Toolkit.getDefaultToolkit().getImage(“src/pieces/black_bishop.png”);
}
公共国际公司董事会(){
返回坐标-((int)坐标/8)*8;
}
公共国际公司董事会(){
返回(int)坐标/8;
}
公共int co_x_draw(){
返回co_x_板()*方形尺寸+((int)方形尺寸/6);
}
公共int co_y__draw(){
返回绘图坐标[co_y_board()]*正方形大小+((int)正方形大小/6);
}
公共空间绘制(图g){
g、 drawString(type,co_x_draw(),co_y_draw());//有效
g、 drawImage(image,co_x_draw(),co_y_draw(),工件尺寸,工件尺寸,null);//不工作
}
}

提前谢谢你

问题在于,您没有提供
drawImage
方法调用的
ImageObserver
参数

我可以重现您在MRE中看到的错误

我曾经通过
Toolkit.getDefaultToolkit().getImage(“…”)阅读过图像(或
Toolkit.getDefaultToolkit().createImage(“…”;
),有时如果您不提供
ImageObserver
,或者在绘制图像之前不调用图像上的示例
getWidth(null)
,以及其他我不知道原因的症状,那么它就不起作用。但我知道的是,如果您提供
ImageObserver
参数,那么它将起作用

请记住,
组件
是一个
图像观察者
。。。因此,您需要将
组件
(图形
对象所属的)实际提供给
drawImage
最后一个参数

因此,您可以更改
Piece#draw
方法以接受绘制它的
组件,如下所示:

public void draw(Graphics g, final Component observer) {
    g.drawString(type, co_x_draw(), co_y_draw());
    g.drawImage(image, co_x_draw(), co_y_draw(), piece_size, piece_size, observer);
}
然后记得正确地调用它,方法是更改
棋盘#paintComponent
,如下所示:

@Override
public void paintComponent(Graphics g) {
    super.paintComponent(g);
    for (Square square : squares) {
        square.draw(g);
    }
    piece.draw(g, this);
}
通常纠正错误的另一种方法是,即使使用
null
作为
ImageObserver
,也可以使用
ImageIO#read
方法将图像作为
BufferedImage
读取。再说一遍,我不知道为什么会这样,但确实如此。我也没有使用
ImageIO#read
测试您的案例,但我仍然使用
Toolkit.getDefaultTooklit().getImage(“…”)测试它
并且它可以工作(但是您需要提供
ImageObserver
参数)

一些建议: 在我看来,用
GridLayout
(例如
newgridlayout(0,8);
)在
JPanel
中布局一些
JLabel
s,然后将图像设置为
Icon
s(通过
myLabel.setIcon(newimageicon(myImage));