Java repaint() 没有调用 paintComponent()
Java repaint() not calling paintComponent()
为了尝试制作一个非常简单的子弹地狱游戏来了解 java,我 运行 遇到了障碍:repaint() 没有调用 paintComponent()。
这是整个程序,现在只是将我每秒创建 50 次的图像绘制到基于 JFrame 的 JPanel 上。
/*
* Bullet hell, by Nematodes
*/
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.Toolkit;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import javax.imageio.ImageIO;
import javax.swing.JFrame;
import javax.swing.JPanel;
public class bulletHell extends JFrame
{
private static final long serialVersionUID = 0L;
JPanel gamePanel = new JPanel();
int gameTimerDelay = 20;
int x, y = 0;
BufferedImage lightOrb;
javax.swing.Timer gameTimer;
public static void main(String[] args)
{
bulletHell createFrame = new bulletHell();
createFrame.frameConstructor();
}
public void frameConstructor()
{
// Construct frame and frame components
setTitle("Bullet hell");
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setResizable(false);
getContentPane().setLayout(new GridBagLayout());
setVisible(true);
GridBagConstraints gridConstraints;
gridConstraints = new GridBagConstraints();
gridConstraints.gridx = 0;
gridConstraints.gridy = 0;
gamePanel.setBackground(Color.BLACK);
gamePanel.setPreferredSize(new Dimension(700, 700));
getContentPane().add(gamePanel, gridConstraints);
pack();
Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize();
setBounds((int) (0.5 * (screenSize.width - getWidth())),
(int) (0.5 * (screenSize.height - getHeight())), getWidth(), getHeight());
try
{
lightOrb = ImageIO.read(new File("C:/Users/Owner/Downloads/orb.bmp"));
}
catch(IOException e)
{
System.out.println("An issue occurred while trying to read orb.bmp");
}
// Start timer that draws game objects 50 times per second (50 FPS)
gameTimer = new javax.swing.Timer(gameTimerDelay, gameTimerAction);
gameTimer.setInitialDelay(0);
gameTimer.start();
}
ActionListener gameTimerAction = new ActionListener()
{
public void actionPerformed(ActionEvent e)
{
repaint();
}
};
class GraphicsPanel extends JPanel
{
public GraphicsPanel()
{
}
// Draw all of the components
@Override
public void paintComponent(Graphics g)
{
Graphics2D g2D = (Graphics2D) g;
super.paintComponent(g2D);
g2D.drawImage(lightOrb, x, y, this);
g2D.dispose();
}
}
}
在使用断点和 println 方法进行一些调试之后,我可以确认正在读取正确的图像,gameTimerAction 中的计时器每秒被调用 50 次,并且 repaint() 根本没有调用 paintComponent()。
我对 Java 编程有些陌生,可能只是缺少一些简单的东西。
编辑:问题已通过将 gamePanel 更改为 GraphicsPanel 对象而得到解决。不幸的是,这也意味着我的更大的 pong 项目(该项目有缺陷的绘图逻辑基本上是从中复制的)只是奇迹般地工作,并且可能会因添加某些代码而不稳定。
我可以立即看出几个问题:
- 最重要:您永远不会实例化 GraphicsPanel 对象,也不会将其添加到任何对象。
paintComponent(...)
方法永远不会在既未呈现也未创建的 JPanel 上调用。为什么不将 gamePanel 变量设为 GraphicsPanel 对象而不是 JPanel 对象?
- 您永远不会更改计时器中的 x 和 y,因此如果不更改,就不会出现动画。
- 您还对 JVM 提供给您的 Graphics 对象调用了 dispose,这是您永远不应该做的事情。这会破坏 Swing 绘画链,使您的 GUI 图形不稳定。
所以坚持下去,你会到达那里。
例如:
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.net.URL;
import javax.imageio.ImageIO;
import javax.swing.*;
public class BulletExample extends JPanel {
public static final String IMG_PATH = "http://www.i2clipart.com/cliparts/f/0/5/8/clipart-blue-circle-f058.png";
private static final int PREF_W = 700;
private static final int PREF_H = PREF_W;
private static final int TIMER_DELAY = 20;
private BufferedImage bullet;
private int bulletX;
private int bulletY;
public BulletExample() throws IOException {
URL imgUrl = new URL(IMG_PATH);
bullet = ImageIO.read(imgUrl);
new Timer(TIMER_DELAY, new BulletListener()).start();
}
@Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
if (bullet != null) {
g.drawImage(bullet, bulletX, bulletY, this);
}
}
@Override
public Dimension getPreferredSize() {
if (isPreferredSizeSet()) {
return super.getPreferredSize();
}
return new Dimension(PREF_W, PREF_H);
}
private class BulletListener implements ActionListener {
@Override
public void actionPerformed(ActionEvent e) {
bulletX++;
bulletY++;
repaint();
}
}
private static void createAndShowGui() throws IOException {
// create the drawing JPanel
BulletExample mainPanel = new BulletExample();
JFrame frame = new JFrame("BulletExample");
frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
// add it to the JFrame
frame.getContentPane().add(mainPanel);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
try {
createAndShowGui();
} catch (IOException e) {
e.printStackTrace();
}
}
});
}
}
为了尝试制作一个非常简单的子弹地狱游戏来了解 java,我 运行 遇到了障碍:repaint() 没有调用 paintComponent()。
这是整个程序,现在只是将我每秒创建 50 次的图像绘制到基于 JFrame 的 JPanel 上。
/*
* Bullet hell, by Nematodes
*/
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.Toolkit;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import javax.imageio.ImageIO;
import javax.swing.JFrame;
import javax.swing.JPanel;
public class bulletHell extends JFrame
{
private static final long serialVersionUID = 0L;
JPanel gamePanel = new JPanel();
int gameTimerDelay = 20;
int x, y = 0;
BufferedImage lightOrb;
javax.swing.Timer gameTimer;
public static void main(String[] args)
{
bulletHell createFrame = new bulletHell();
createFrame.frameConstructor();
}
public void frameConstructor()
{
// Construct frame and frame components
setTitle("Bullet hell");
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setResizable(false);
getContentPane().setLayout(new GridBagLayout());
setVisible(true);
GridBagConstraints gridConstraints;
gridConstraints = new GridBagConstraints();
gridConstraints.gridx = 0;
gridConstraints.gridy = 0;
gamePanel.setBackground(Color.BLACK);
gamePanel.setPreferredSize(new Dimension(700, 700));
getContentPane().add(gamePanel, gridConstraints);
pack();
Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize();
setBounds((int) (0.5 * (screenSize.width - getWidth())),
(int) (0.5 * (screenSize.height - getHeight())), getWidth(), getHeight());
try
{
lightOrb = ImageIO.read(new File("C:/Users/Owner/Downloads/orb.bmp"));
}
catch(IOException e)
{
System.out.println("An issue occurred while trying to read orb.bmp");
}
// Start timer that draws game objects 50 times per second (50 FPS)
gameTimer = new javax.swing.Timer(gameTimerDelay, gameTimerAction);
gameTimer.setInitialDelay(0);
gameTimer.start();
}
ActionListener gameTimerAction = new ActionListener()
{
public void actionPerformed(ActionEvent e)
{
repaint();
}
};
class GraphicsPanel extends JPanel
{
public GraphicsPanel()
{
}
// Draw all of the components
@Override
public void paintComponent(Graphics g)
{
Graphics2D g2D = (Graphics2D) g;
super.paintComponent(g2D);
g2D.drawImage(lightOrb, x, y, this);
g2D.dispose();
}
}
}
在使用断点和 println 方法进行一些调试之后,我可以确认正在读取正确的图像,gameTimerAction 中的计时器每秒被调用 50 次,并且 repaint() 根本没有调用 paintComponent()。
我对 Java 编程有些陌生,可能只是缺少一些简单的东西。
编辑:问题已通过将 gamePanel 更改为 GraphicsPanel 对象而得到解决。不幸的是,这也意味着我的更大的 pong 项目(该项目有缺陷的绘图逻辑基本上是从中复制的)只是奇迹般地工作,并且可能会因添加某些代码而不稳定。
我可以立即看出几个问题:
- 最重要:您永远不会实例化 GraphicsPanel 对象,也不会将其添加到任何对象。
paintComponent(...)
方法永远不会在既未呈现也未创建的 JPanel 上调用。为什么不将 gamePanel 变量设为 GraphicsPanel 对象而不是 JPanel 对象? - 您永远不会更改计时器中的 x 和 y,因此如果不更改,就不会出现动画。
- 您还对 JVM 提供给您的 Graphics 对象调用了 dispose,这是您永远不应该做的事情。这会破坏 Swing 绘画链,使您的 GUI 图形不稳定。
所以坚持下去,你会到达那里。
例如:
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.net.URL;
import javax.imageio.ImageIO;
import javax.swing.*;
public class BulletExample extends JPanel {
public static final String IMG_PATH = "http://www.i2clipart.com/cliparts/f/0/5/8/clipart-blue-circle-f058.png";
private static final int PREF_W = 700;
private static final int PREF_H = PREF_W;
private static final int TIMER_DELAY = 20;
private BufferedImage bullet;
private int bulletX;
private int bulletY;
public BulletExample() throws IOException {
URL imgUrl = new URL(IMG_PATH);
bullet = ImageIO.read(imgUrl);
new Timer(TIMER_DELAY, new BulletListener()).start();
}
@Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
if (bullet != null) {
g.drawImage(bullet, bulletX, bulletY, this);
}
}
@Override
public Dimension getPreferredSize() {
if (isPreferredSizeSet()) {
return super.getPreferredSize();
}
return new Dimension(PREF_W, PREF_H);
}
private class BulletListener implements ActionListener {
@Override
public void actionPerformed(ActionEvent e) {
bulletX++;
bulletY++;
repaint();
}
}
private static void createAndShowGui() throws IOException {
// create the drawing JPanel
BulletExample mainPanel = new BulletExample();
JFrame frame = new JFrame("BulletExample");
frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
// add it to the JFrame
frame.getContentPane().add(mainPanel);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
try {
createAndShowGui();
} catch (IOException e) {
e.printStackTrace();
}
}
});
}
}