Java将JPanel传递给子类

3

我正在使用Java进行一些面向对象编程。

我只想写一个带有一些图形对象的游戏,但我想用一些类来结构化它。

整体布局应如下:

MainClass -> new MainPanel(扩展JPanel)- > new StartWindow(扩展抽象GameWindow,其中包含gameloop)

这样,我应该能够创建StartWindow、Level1Window、Level2Window等窗口。我的StartWindow现在应该绘制第一级别的布局。StartWindow将创建其他对象(例如玩家、敌人等),它们以后将负责绘制自己。

所以,我想创建“每个对象都负责绘制自己”的东西。

我希望我已经清楚地解释了这个过程。问题是,我无法弄清楚如何委派这个任务。

目前我的代码看起来像这样:

public class MainClass extends JFrame implements ActionListener {
    //..... other stuff
    public MainClass () {
        MainPanel mainPanel = new MainPanel();
    }
    //.... other stuff
}


class MainPanel extends JPanel {

    private GameWindow currentWindow;

    public MainPanel () {
        currentWindow = new StartWindow(this);
    }

    public void paintComponent(Graphics g) {
        g.drawRect (10, 10, 200, 200);  // <-- can see on the window
    }
}


abstract class GameWindow {
    // contains game loop and update functions and so on
}


public class StartWindow extends GameWindow {

    GamePanel _parentWindow;

    public StartWindow(GamePanel parentWindow) {
        super();
        _parentWindow = parentWindow;
    }

    public void paintComponent(Graphics g) {
        //Does not work
        g.drawRect (20, 20, 100, 100);  
    }
}

"_parentWindow" 包含 MainPanel,因此我应该拥有在其面板上绘制所需的所有信息,但我无法弄清如何实现。
编辑: 最小示例可以正常工作:
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;

public class MainClass extends JFrame implements ActionListener {

public static void main(String[] args)
   {
       System.out.println("Program Window1");
       MainClass glt = new MainClass();
       glt.setVisible(true);
   }

//..... other stuff
public MainClass () {
    super("Fixed Timestep Game Loop Test");
    Container cp = getContentPane();
    cp.setLayout(new BorderLayout());
    JPanel p = new JPanel();
    p.setLayout(new GridLayout(1,2));



    System.out.println("Program Window2");
    MainPanel gamePanel= new MainPanel();

    cp.add(gamePanel, BorderLayout.CENTER);
    cp.add(p, BorderLayout.SOUTH);
    setSize(500, 500);
}
//.... other stuff

@Override
public void actionPerformed(ActionEvent arg0) {
    // TODO Auto-generated method stub

}
}


class MainPanel extends JPanel {

private GameWindow currentWindow;

public MainPanel () {
    currentWindow = new StartWindow(this);
}

public void paintComponent(Graphics g) {
    g.drawRect (0, 0, 200, 200);  // <-- can see on the window
}
}


abstract class GameWindow {
// contains game loop and update functions and so on
}


class StartWindow extends GameWindow {

MainPanel _parentWindow;

public StartWindow(MainPanel parentWindow) {
    super();
    _parentWindow = parentWindow;
}

public void paintComponent(Graphics g) {
    //Does not work
    g.drawRect (20, 20, 100, 100);  
}
}

请查看此网站:http://zetcode.com/tutorials/javagamestutorial/ - user2277872
只是一般性的建议——不要过于关注扩展Swing组件,而是更多地关注游戏逻辑结构的继承。你甚至可以(也应该)创建可绘制的逻辑结构,它们不需要从JComponent继承,但你可以通过自己的“Drawable”接口继承绘画方法。 - Hovercraft Full Of Eels
说实话,我认为我的继承结构很好。一个包含面板窗口的程序窗口用于绘制。这个面板窗口包含级别窗口,我可以根据需要创建和添加。每个级别窗口都继承自我的游戏循环窗口。 - Hunselfunsel
明确的问题是:我如何在StartWindow类中的JPanel上绘制。 - Hunselfunsel
谢谢。为了努力工作,我会加1个赞。 - Hovercraft Full Of Eels
显示剩余3条评论
2个回答

2
在您的MainPanel类的paintComponent方法中尝试像这样的代码。
public void paintComponent(Graphics g) {
  g.drawRect (10, 10, 200, 200);  // <-- can see on the window
  Graphics2D g2d = (Graphics2D) g.create();
  ((StartWindow) currentWindow).paintComponent(g2d);
  g2d.dispose();
}

这段代码看起来很危险——直接调用paintComponent,而JVM应该负责此操作,并在此过程中忽略组件边框和子组件的绘制。您能解释一下为什么建议这样做吗? - Hovercraft Full Of Eels
StartWindow的paintComponent方法与JComponent类的paintComponent方法无关。我认为他试图将StartWindow用作精灵。 - Sebastian Gnitkowitz

2
我会在您的主绘图JComponent中绘制精灵,例如,

import javax.swing.*;
import java.awt.*;
import java.awt.event.*;

public class MainClass extends JFrame implements ActionListener {

    public static void main(String[] args) {
        System.out.println("Program Window1");
        MainClass glt = new MainClass();
        glt.setVisible(true);
    }

    // ..... other stuff
    public MainClass() {
        super("Fixed Timestep Game Loop Test");
        setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
        Container cp = getContentPane();
        cp.setLayout(new BorderLayout());
        JPanel p = new JPanel();
        p.setLayout(new GridLayout(1, 2));

        System.out.println("Program Window2");
        MainPanel gamePanel = new MainPanel();

        cp.add(gamePanel, BorderLayout.CENTER);
        cp.add(p, BorderLayout.SOUTH);
        setSize(500, 500);
    }

    // .... other stuff

    @Override
    public void actionPerformed(ActionEvent arg0) {
        // TODO Auto-generated method stub

    }
}

class MainPanel extends JPanel {

    private GameWindow currentWindow;

    public MainPanel() {
        currentWindow = new StartWindow(this);
    }

//    public void paintComponent(Graphics g) {
//        g.drawRect(0, 0, 200, 200); // <-- can see on the window
//    }

    // this should be protected, not public and should call super method 
    @Override  
    protected void paintComponent(Graphics g) {
        super.paintComponent(g);
        g.drawRect(0, 0, 200, 200); // <-- can see on the window
        currentWindow.draw(g);
    }
}

interface Drawable {
    void draw(Graphics g);
}

abstract class GameWindow implements Drawable {
    // contains game loop and update functions and so on
}

class StartWindow extends GameWindow {

    MainPanel _parentWindow;

    public StartWindow(MainPanel parentWindow) {
        super();
        _parentWindow = parentWindow;
    }

    @Override
    public void draw(Graphics g) {
        g.setColor(Color.red);
        g.drawRect(20, 20, 100, 100);
    }
}

但是,我再次强调,游戏循环不应该被继承,而是应该传递它的引用。通过组合进行扩展,而不是继承。

或者更好的方法是,让你的模型类实现一个接口,例如:

public interface Tickable {
    void tick(int deltaTime);
}

主模型持有类似 List<Tickable> 的集合,每当游戏循环进行时,它会遍历这个列表,并在列表中的每个项目上调用tick(...)


非常感谢,我尝试理解你在做什么。你能解释一下“gameloop reference”的意思吗?你能修改你的代码,让我理解你想用引用表达的意思吗? - Hunselfunsel
@Hunselfunsel:也许有一个更好的想法——请看编辑。 - Hovercraft Full Of Eels

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接