Java JPanel在绘制图像时显示奇怪错误

Java JPanel在绘制图像时显示奇怪错误,java,swing,jpanel,paintcomponent,grid-layout,Java,Swing,Jpanel,Paintcomponent,Grid Layout,我的棋盘游戏有个奇怪的错误。该板由一个带有GameTiles的2D数组组成,GameTiles是JPanel的一个子类。当我有这个尺寸(600500)时,一切都很好,但每当我改变它时,左上角就会出现一个奇怪的错误 错误图片(见左上角) 更奇怪的是,当我创建一个新项目时,只是为了尝试一下,它工作得非常好。代码与绘画完全相同,我没有遇到任何错误。是否是其他原因导致了这个问题 问题已修复 Anser:我意外地覆盖了JPanel的getX和getY方法。我把它们的名字改了,现在它工作得很好 Rever

我的棋盘游戏有个奇怪的错误。该板由一个带有GameTiles的2D数组组成,GameTiles是JPanel的一个子类。当我有这个尺寸(600500)时,一切都很好,但每当我改变它时,左上角就会出现一个奇怪的错误

错误图片(见左上角)

更奇怪的是,当我创建一个新项目时,只是为了尝试一下,它工作得非常好。代码与绘画完全相同,我没有遇到任何错误。是否是其他原因导致了这个问题

问题已修复

Anser:我意外地覆盖了JPanel的getX和getY方法。我把它们的名字改了,现在它工作得很好

Reversi.java

package org.reversi;

import javax.swing.JFrame;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;

import org.reversi.gui.GameFrame;

public class Reversi {
public static void main(String[] args) {
    try {
                 UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
    } catch (ClassNotFoundException e) {
        e.printStackTrace();
    } catch (InstantiationException e) {
        e.printStackTrace();
    } catch (IllegalAccessException e) {
        e.printStackTrace();
    } catch (UnsupportedLookAndFeelException e) {
        e.printStackTrace();
    }

    java.awt.EventQueue.invokeLater(new Runnable() {
        @Override
        public void run() {
            GameFrame frame = new GameFrame("Reversi");
            frame.setSize(600,500);
            frame.setLocationRelativeTo(null);
            frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
            frame.setVisible(true);
        }
    });
}
}
GameBoard.java

package org.reversi.gui;

import java.awt.Graphics;
import java.awt.GridLayout;

import javax.swing.JPanel;

public class GameBoard extends JPanel{
private GameTile[][] gameBoard = new GameTile[8][8];

public GameBoard() {
    initiateLayout();
}

private void initiateLayout() {
    setLayout(new GridLayout(8, 8));

    for(int row = 0 ; row < 8 ; row++) {
        for(int col = 0 ; col < 8 ; col++) {
            gameBoard[row][col] = new GameTile(col,row);
            add(gameBoard[row][col]);
        }
    }
}

@Override
protected void paintComponent(Graphics g) {
    super.paintComponent(g);
    for(int row = 0 ; row < 8 ; row++) 
        for(int col = 0 ; col < 8 ; col++)              
            gameBoard[row][col].repaint();
}
}
GameTile.java

package org.reversi.gui;

import java.awt.Graphics;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;

import javax.imageio.ImageIO;
import javax.swing.JPanel;

public class GameTile extends JPanel {
private BufferedImage image;
private int x;
private int y;

public GameTile(int x, int y) {
    this.x = x;
    this.y = y;
    try {
        this.image = ImageIO.read(new File("tile.png"));
    } catch (IOException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    }
}

@Override
protected void paintComponent(Graphics g) {
    super.paintComponent(g);
    g.drawImage(image, 0, 0, getWidth(), getHeight(), this);
}

public int getX() {
    return x;
}

public int getY() {
    return y;
}
}
链接到图像(应命名为tile.png):

根据您的评论:


这就是问题所在,非常感谢您指出这一点。我是 在板上移动时使用坐标。如果有 这是一个很好的答案

GameTile.java
中,您已经完成了:

public int getX() {
    return x;
}

public int getY() {
    return y;
}
这样,您实际上覆盖了
JPanel
s并返回坐标,这将影响
布局
。这可以通过添加(注意,不会引发编译器错误,因此我们正确地重写了扩展类中的方法):

正如@Xeon所说的,您不应该设置坐标,
LayoutManager
会这样做

解决方案:(外加额外费用)

  • 删除这些getter或适当地重命名它们

  • 不要在
    JFrame
    上调用
    setSize
    ,而要覆盖通过
    Graphic
    s对象绘制的
    JPanel的
    getPreferredSize
    ,并返回正确的
    维度
    s(在您的情况下是图像维度),然后调用[
    pack()
    ][4]在
    JFrame`上,在将其设置为可见之前,但在添加组件之后

  • 您需要将对
    setLocationRelativeTo(…)
    的调用重新定位到
    pack()
    之后

  • 最好使用
    JFrame.DISPOSE\u ON\u CLOSE
    以便
    main(String[]args)
    方法可以在GUI终止后继续执行

  • 也不要不必要地扩展
    JFrame

  • 不要在
    GameTile
    类中重复加载相同的图像,而是加载一次图像,并为
    GameTile
    添加参数,以接受
    buffereImage
    (我在使用internet URL进行测试时发现了这一点,因为它会为每个
    GameTile
    创建的对象读取一个新图像,所以它花费了很长时间)

以下是进行了必要更改的课程:

Reversi.java:

public class Reversi {

    public static void main(String[] args) {
        try {
            UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        } catch (InstantiationException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        } catch (UnsupportedLookAndFeelException e) {
            e.printStackTrace();
        }

        java.awt.EventQueue.invokeLater(new Runnable() {
            @Override
            public void run() {
                new GameFrame("Reversi");
            }
        });
    }
}
public class GameTile extends JPanel {

    private BufferedImage image;
    private int x;
    private int y;

    public GameTile(BufferedImage image, int x, int y) {
        this.image = image;
        this.x = x;
        this.y = y;
    }

    @Override
    public Dimension getPreferredSize() {
        return new Dimension(image.getWidth(), image.getHeight());
    }

    @Override
    protected void paintComponent(Graphics g) {
        super.paintComponent(g);
        g.drawImage(image, 0, 0, getWidth(), getHeight(), this);
    }
}
public class GameFrame {

   private GameBoard gameBoard;

    /**
     * Creates a new frame.
     *
     * @param gameTitle the title of the frame
     */
    public GameFrame(String gameTitle) {
        JFrame frame = new JFrame(gameTitle);
        frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
        gameBoard = new GameBoard();
        frame.add(gameBoard);
        frame.pack();
        frame.setLocationRelativeTo(null);
        frame.setVisible(true);
    }
}
GameBoard.java

public class GameBoard extends JPanel {

    private GameTile[][] gameBoard = new GameTile[8][8];

    public GameBoard() {
        initiateLayout();
    }

    private void initiateLayout() {
        setLayout(new GridLayout(8, 8));

        BufferedImage image = null;
        try {
            image = ImageIO.read(new URL("http://i.imgur.com/ejmCtui.png"));
        } catch (IOException e) {
            e.printStackTrace();
        }
        for (int row = 0; row < 8; row++) {
            for (int col = 0; col < 8; col++) {
                gameBoard[row][col] = new GameTile(image, col, row);
                add(gameBoard[row][col]);
            }
        }
    }

    @Override
    protected void paintComponent(Graphics g) {
        super.paintComponent(g);
        for (int row = 0; row < 8; row++) {
            for (int col = 0; col < 8; col++) {
                gameBoard[row][col].repaint();
            }
        }
    }
}
GameFrame.java:

public class Reversi {

    public static void main(String[] args) {
        try {
            UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        } catch (InstantiationException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        } catch (UnsupportedLookAndFeelException e) {
            e.printStackTrace();
        }

        java.awt.EventQueue.invokeLater(new Runnable() {
            @Override
            public void run() {
                new GameFrame("Reversi");
            }
        });
    }
}
public class GameTile extends JPanel {

    private BufferedImage image;
    private int x;
    private int y;

    public GameTile(BufferedImage image, int x, int y) {
        this.image = image;
        this.x = x;
        this.y = y;
    }

    @Override
    public Dimension getPreferredSize() {
        return new Dimension(image.getWidth(), image.getHeight());
    }

    @Override
    protected void paintComponent(Graphics g) {
        super.paintComponent(g);
        g.drawImage(image, 0, 0, getWidth(), getHeight(), this);
    }
}
public class GameFrame {

   private GameBoard gameBoard;

    /**
     * Creates a new frame.
     *
     * @param gameTitle the title of the frame
     */
    public GameFrame(String gameTitle) {
        JFrame frame = new JFrame(gameTitle);
        frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
        gameBoard = new GameBoard();
        frame.add(gameBoard);
        frame.pack();
        frame.setLocationRelativeTo(null);
        frame.setVisible(true);
    }
}
这将产生:


在paintComponent中调用repaint()没有任何意义。只需调用一个重绘(在容器中)。但这并不能解释你的问题:我想它一定在别的地方。请尽快发布一个更好的帮助。这可能还包括链接到外部图像或从sscce的代码+1中创建您自己的小图像…为什么您有
getX
getY
?顺便说一句,它正在覆盖扩展的
JPanel
s
getX
getY
方法。。。。而不是你的
x
y
。添加
@Override
注释(在方法声明上方),您将不会看到编译错误…+1@Xeon同时回答:p您已从
JPanel
重写
getX()
方法(或者更准确地说:从
JComponent#getX()
):“返回组件原点的当前x坐标。”但是你不应该这样做,因为布局管理器会负责组件的放置。这就是问题所在,非常感谢你指出这一点。我在板上移动时使用坐标。如果有什么办法可以回答这个问题,那就太好了。