【发布时间】:2018-10-16 01:51:25
【问题描述】:
更新:正如 Dmich 所指出的,因为我在面板类之外进行绘图,这会导致对 MyPanel 和 Animation 类的初始化的递归调用。那么我怎样才能在 MyPanel 上完成绘图,在 Animation 类中,但没有这个问题。
我的代码有一个非常具体的问题,我不知道如何描述正在发生的事情,但我会尽力而为。我尝试搜索 stackOverFLow,但问题是我什至不知道要搜索 什么。
我去:
为了尽可能地组织这一点,我将首先编写我正在处理的所有类。
public class MyPanel extends JPanel implements Runnable{
private Animation anim = new Animation();
}
public class Animation extends ??? implements KeyListener{}
所以我有一个名为 MyPanel 的类,它扩展了 JPanel。我已经将这个类添加到我的 JFrame 中使用
add(new MyPanel())
我在 MyPanel 中使用一个线程,它调用
@Overrid public void paintComponent(Graphics g)
paintComponent 调用 Animation 中的一个方法,我在该方法中将图像绘制到屏幕g2d.drawImage(image, int, int, ImageObserver)。问题是使用这种方法我需要一个 ImageObserver,如果 Animation 扩展了 JPanel,我可以得到它。但是,如果我扩展 JPanel,则不会在我的 JFrame 上绘制任何内容,因为这是一个未添加到 JFrame 的新 jPanel。
但如果我扩展 MyPanel(添加到我的 JFrame 中)我会得到一大堆错误。
Eclipse 错误:
Exception in thread "main" java.lang.StackOverflowError
at java.awt.Component.setBackground(Unknown Source)
at javax.swing.JComponent.setBackground(Unknown Source)
at javax.swing.LookAndFeel.installColors(Unknown Source)
at javax.swing.LookAndFeel.installColorsAndFont(Unknown Source)
at javax.swing.plaf.basic.BasicPanelUI.installDefaults(Unknown Source)
at javax.swing.plaf.basic.BasicPanelUI.installUI(Unknown Source)
at javax.swing.JComponent.setUI(Unknown Source)
at javax.swing.JPanel.setUI(Unknown Source)
at javax.swing.JPanel.updateUI(Unknown Source)
at javax.swing.JPanel.<init>(Unknown Source)
at javax.swing.JPanel.<init>(Unknown Source)
at javax.swing.JPanel.<init>(Unknown Source)
在此错误消息下,这两行一直持续到被 eclipse 终止。
at MyPanel.<init>(MyPanel.java:9)
at Animation.<init>(Animation.java:9)
任何帮助将不胜感激。
更新 2 按照建议添加代码示例:
import javax.swing.JFrame;
public class Simulation extends JFrame {
private MyPanel panel = new MyPanel();
public Simulation() {
initUI();
}
private void initUI() {
add(panel);
setResizable(false);
pack();
setTitle("Simulation");
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setLocationRelativeTo(null); // centers
}
public static void main(String[] args) {
Simulation ex = new Simulation();
ex.setVisible(true);
}
}
import javax.swing.*;
import java.awt.*;
public class MyPanel extends JPanel implements Runnable {
private Animation anim;
public MyPanel() {
anim = new Animation();
initPanel();
}
private void initPanel() {
//other customizables
}
@Override
public void run() {
//Thread that calls repaint();
}
@Override
public void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2D = (Graphics2D) g;
anim.step(g2D, this);
}
}
import java.awt.Graphics2D;
public class Animation {
private Sprite player;
private KeyBinder kB;
public Animation() {
player = new Sprite();
kB = new KeyBinder(player);
}
public void step(Graphics2D g2d, JPanel p) {
player.move();
drawSprite(g2d, p);
}
private void drawSprite(Graphics2D g2d, JPanel p) {
g2d.drawImage(player.getImage(), player.getX(), player.getY(), p);
}
}
import java.awt.Image;
import java.awt.event.KeyEvent;
import javax.swing.ImageIcon;
public class Sprite {
private final String PLAYER_IMAGE_FILE = "Image location";
private Image image;
private int width, height;
private int x, y, dx, dy;
public Sprite() {
x = 0;
y = 0;
loadImage();
}
private void loadImage() {
ImageIcon ii = new ImageIcon(PLAYER_IMAGE_FILE);
image = ii.getImage();
width = image.getWidth(null);
height = image.getHeight(null);
}
public void move() {
x += dx;
y += dy;
}
public void keyPressed(KeyEvent e) {
//assings meaning to keypressed
}
public void keyReleased(KeyEvent e) {
//assings meaning to keyReleased
}
public int getX() {
return x;
}
public int getY() {
return y;
}
public int getW() {
return width;
}
public int getH() {
return height;
}
public Image getImage() {
return image;
}
}
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
public class KeyBinder extends MyPanel implements KeyListener {
Sprite p;
public KeyBinder(Sprite player) {
p = player;
addKeyListener(this);
setFocusable(true);
setFocusTraversalKeysEnabled(false);
}
@Override
public void keyPressed(KeyEvent e) {
p.keyPressed(e);
}
@Override
public void keyReleased(KeyEvent e) {
p.keyReleased(e);
}
@Override
public void keyTyped(KeyEvent e) {
}
}
通过尝试对代码进行故障排除,我对代码进行了更改,主要是通过尝试将 JPanel 传递给 Animation.step 方法并为按键监听创建一个单独的类。
新的错误列表大体相同:
Exception in thread "main" java.lang.StackOverflowError
at java.awt.Component.setBackground(Unknown Source)
at javax.swing.JComponent.setBackground(Unknown Source)
at javax.swing.LookAndFeel.installColors(Unknown Source)
at javax.swing.LookAndFeel.installColorsAndFont(Unknown Source)
at javax.swing.plaf.basic.BasicPanelUI.installDefaults(Unknown Source)
at javax.swing.plaf.basic.BasicPanelUI.installUI(Unknown Source)
at javax.swing.JComponent.setUI(Unknown Source)
at javax.swing.JPanel.setUI(Unknown Source)
at javax.swing.JPanel.updateUI(Unknown Source)
at javax.swing.JPanel.<init>(Unknown Source)
at javax.swing.JPanel.<init>(Unknown Source)
at javax.swing.JPanel.<init>(Unknown Source)
然后是一个无限循环,直到以下三行终止:
at MyPanel.<init>(MyPanel.java:10)
at KeyBinder.<init>(KeyBinder.java:6)
at Animation.<init>(Animation.java:11)
【问题讨论】:
-
because this is a new jPanel which is not added to the JFrame.- 为什么要创建一个新的 JPanel?创建框架时,应创建一次具有自定义绘画的面板。然后将面板添加到框架中。阅读 Custom Painting 上的 Swing 教程部分。为基础。一旦您了解了基础知识,如果您需要动画,那么您可以使用Swing Timer。该教程还有一个关于How to Use Swing Timers的部分。 -
当你有动画扩展面板时,面板包含一个被初始化的动画。由于每个动画都是一个面板,并且每个面板在初始化时都会初始化一个新动画,因此您可以递归调用动画和面板初始化。
-
并且不要将您的自定义面板称为“面板”。名称中有一个 AWT 类,令人困惑。类名应该更具描述性。
-
@camickr 我正在使用线程来制作动画,所以不会使用 Swing Timer。我所说的“新 JPanel”的意思是我没有扩展使用(添加新面板())添加到我的 JFrame 的 JPanel。感谢您的回复,将更改面板名称。
-
@Dmich 这解释了为什么我有一个无限的初始化循环以及为什么 Eclipse 终止了我的程序。感谢您的回复!