簡體   English   中英

擴展JPanel以繪制圖像。 但是在同一面板上添加到JFrame

[英]Extending JPanel to draw Image. But on the same Panel added to JFrame

更新 :正如Dmich所指出的,因為我在我的面板類之外進行繪制,所以這導致對MyPanel和Animation類的初始化進行遞歸調用。 因此,如何仍然可以在Animation類的MyPanel上完成繪制,但是沒有這個問題。

我的代碼有一個非常具體的問題,我不知道如何描述正在發生的事情,但是我會盡力而為。 我嘗試搜索stackOverFLow,但問題是我至不知道要搜索什么

我來啦:

為了盡力組織起來,我將首先編寫我要處理的所有類。

public class MyPanel extends JPanel implements Runnable{
private Animation anim = new Animation();
}
public class Animation extends ??? implements KeyListener{}

因此,我有一個名為MyPanel的類,該類擴展了JPanel。 我已經使用add(new MyPanel())此類添加到了JFrame中,我在MyPanel中使用了一個線程,該線程調用@Overrid @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) 

在此錯誤消息下,這兩行一直持續到被月食終止為止。

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)

因此,我有一個名為Panel的類,該類擴展了JPanel。 我已經使用add(new Panel())將此類添加到了JFrame中,我在Panel中使用了一個線程,該線程調用@Overrid public void paintComponent(Graphics g)

首先,Swing不是線程安全的,您不應從事件調度線程的上下文外部更新UI。

其次,決不應該存在直接調用paintComponent情況,也不需要public它,因為沒有別的東西可以調用它。

有關更多詳細信息,請參見Swing中的並發。

paintComponent在Animation中調用一個方法,在該方法中,我將圖像繪制到屏幕上g2d.drawImage(image,int,int,ImageObserver)。 問題是使用此方法時,我需要一個ImageObserver,如果Animation擴展了JPanel,則可以獲取它。

為什么不讓Animation “可繪畫的”,從而提供一種方法,該方法要求調用者傳遞您所需的信息才能完成工作?

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

您還可以將其他可能需要的信息傳遞給paint方法,例如對當前狀態建模的模型。

這基本上是一個委派模型-在這里,您將特定任務的責任“委托”給另一個班級

那么KeyListener呢?

我聽到你問。

好吧,首先,處理它可能不是Animation的責任。 相反,控制器應該響應事件來修改狀態,該狀態最終由渲染器繪制

另外,您應該改用Key bindings API ,它將解決與KeyListener相關的不可靠性問題

我不建議使類擴展JPanel,而是在實例化時使用JPanel參數:

public class Panel implements Runnable{
    private JPanel panel;

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

另外,我認為使Panel類具有Extend Component是明智的,以便在將其添加到標題中提到的現有面板時進行無縫集成:

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

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

如果這不起作用,或者您對此還有其他疑問,請告訴我!

這是繼承不良小伙子的另一起案件。 我通過在MYPanel類中實現KeyListener並將MyPanel作為Animation的參數傳遞來修復了它。 對我來說,嘗試從另一個類實現JPanel的keyListener是不好的做法。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM