Java JPanel在绘制图像时显示奇怪错误
我的棋盘游戏有个奇怪的错误。该板由一个带有GameTiles的2D数组组成,GameTiles是JPanel的一个子类。当我有这个尺寸(600500)时,一切都很好,但每当我改变它时,左上角就会出现一个奇怪的错误 错误图片(见左上角) 更奇怪的是,当我创建一个新项目时,只是为了尝试一下,它工作得非常好。代码与绘画完全相同,我没有遇到任何错误。是否是其他原因导致了这个问题 问题已修复 Anser:我意外地覆盖了JPanel的getX和getY方法。我把它们的名字改了,现在它工作得很好 Reversi.javaJava JPanel在绘制图像时显示奇怪错误,java,swing,jpanel,paintcomponent,grid-layout,Java,Swing,Jpanel,Paintcomponent,Grid Layout,我的棋盘游戏有个奇怪的错误。该板由一个带有GameTiles的2D数组组成,GameTiles是JPanel的一个子类。当我有这个尺寸(600500)时,一切都很好,但每当我改变它时,左上角就会出现一个奇怪的错误 错误图片(见左上角) 更奇怪的是,当我创建一个新项目时,只是为了尝试一下,它工作得非常好。代码与绘画完全相同,我没有遇到任何错误。是否是其他原因导致了这个问题 问题已修复 Anser:我意外地覆盖了JPanel的getX和getY方法。我把它们的名字改了,现在它工作得很好 Rever
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
维度
pack()s(在您的情况下是图像维度),然后调用[
JFrame`上,在将其设置为可见之前,但在添加组件之后][4]在
- 您需要将对
的调用重新定位到setLocationRelativeTo(…)
之后pack()
- 最好使用
以便JFrame.DISPOSE\u ON\u CLOSE
方法可以在GUI终止后继续执行main(String[]args)
- 也不要不必要地扩展
JFrame
- 不要在
类中重复加载相同的图像,而是加载一次图像,并为GameTile
添加参数,以接受GameTile
(我在使用internet URL进行测试时发现了这一点,因为它会为每个buffereImage
创建的对象读取一个新图像,所以它花费了很长时间)GameTile
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
sgetX
和getY
方法。。。。而不是你的x
和y
。添加@Override
注释(在方法声明上方),您将不会看到编译错误…+1@Xeon同时回答:p您已从JPanel
重写getX()
方法(或者更准确地说:从JComponent#getX()
):“返回组件原点的当前x坐标。”但是你不应该这样做,因为布局管理器会负责组件的放置。这就是问题所在,非常感谢你指出这一点。我在板上移动时使用坐标。如果有什么办法可以回答这个问题,那就太好了。