扩展JPanel以绘制图像。但在同一个Panel上添加了JFrame

时间:2018-05-05 21:29:07

标签: java swing jpanel

UPDATE :正如Dmich所说,因为我在我的面板类之外进行绘图,这导致对我的MyPanel和Animation类的初始化进行递归调用。那么我怎样才能在动画类中完成MyPanel上的绘图,但没有这个问题。

我的代码存在一个非常具体的问题,我不知道如何描述正在发生的事情,但我会尽我所能。我试着搜索stackOverFLow,但问题是我甚至不知道 来搜索。

我走了:

为了尽可能地组织这个,我将首先编写我正在处理的所有课程。

add(new MyPanel())

所以我有一个名为MyPanel的类,它扩展了JPanel。我已经使用了这个类添加到我的JFrame中     @Overrid public void paintComponent(Graphics g) 我在MyPanel中使用一个调用的线程  g2d.drawImage(image, int, int, ImageObserver)  paintComponent在Animation中调用一个方法,我将图像绘制到屏幕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) 。问题是使用这个方法我需要一个ImageObserver,如果Animation扩展了JPanel,我可以得到它。但是如果我扩展JPanel,我的JFrame上没有任何内容,因为这是一个新的jPanel,它没有被添加到JFrame中。

但是如果我扩展MyPanel(它被添加到我的JFrame中),我会收到一大堆错误。

Eclipse错误:

at MyPanel.<init>(MyPanel.java:9)
at Animation.<init>(Animation.java:9)

在此错误消息下,这两行继续,直到eclipse终止。

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) {

}
}

非常感谢任何帮助。

更新2 按建议添加代码示例:

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)

通过尝试解决代码故障我改变了我的代码,主要是尝试将JPanel传递给Animation.step方法,并为密钥监听创建一个单独的类。

新错误列表大致相同:

at MyPanel.<init>(MyPanel.java:10)
at KeyBinder.<init>(KeyBinder.java:6)
at Animation.<init>(Animation.java:11)

然后是无限循环,直到以下三行终止:

{{1}}

3 个答案:

答案 0 :(得分:1)

  

所以我有一个名为Panel的类,它扩展了JPanel。我已经使用add(new Panel())将这个类添加到我的JFrame中我在Panel中调用了一个调用@Overrid的漏洞public void paintComponent(Graphics g)

首先,Swing不是线程安全的,你不应该在Event Dispatching Thread的上下文之外更新UI。

其次,绝不应该直接调用paintComponent,也不需要它public,因为没有别的东西可以调用它。

有关详细信息,请参阅Concurrency in Swing

  

paintComponent在Animation中调用一个方法,在这里我将图像绘制到屏幕g2d.drawImage(image,int,int,ImageObserver)。问题是使用这个方法我需要一个ImageObserver,如果Animation扩展了JPanel,我可以得到它。

为什么不制作Animation&#34; paintable&#34;,提供一种方法,要求来电者传递您所需的信息才能完成工作?

public class Animation {
    public void paint(Graphics2D g2d, ImageObserver observer) {
        //...
    }
}

您还可以传递paint方法可能需要的其他信息,例如模拟当前状态的模型。

这基本上是一个代表模型 - 你在哪里代理&#34;对另一个班级的特定任务负责

  

KeyListener怎么样?

我听到你问。

嗯,首先,它可能不是Animation处理它的责任。相反,控制器应该修改状态,以响应最终由渲染器绘制的事件

此外,您应该使用Key bindings API代替,它将解决与KeyListener

相关的不可靠性问题

答案 1 :(得分:0)

我不建议让类扩展JPanel,而是在实例化时接受JPanel参数:

public class Panel implements Runnable{
    private JPanel panel;

    public Panel(JPanel panel){
        this.panel = panel;
    }
}

此外,我认为让Panel类具有扩展组件是明智之举,以便在将其添加到标题中提到的现有面板时实现无缝集成:

public class Panel extends Component implements Runnable{
    private JPanel panel;

    public Panel(JPanel panel){
        this.panel = panel;
    }
}

如果这不起作用或者您对此有其他疑问,请告诉我!

答案 2 :(得分:0)

这是另一个糟糕的继承小伙伴的案例。我通过在MYPanel类中实现KeyListener并将MyPanel作为参数传递给Animation来修复它。对我来说,尝试将keyListener实现到JPanel但来自不同的类是不好的做法。