【问题标题】:Java pass JPanel down to child classJava将JPanel传递给子类
【发布时间】:2015-09-27 15:58:33
【问题描述】:

我正在使用 java 进行一些 OOP。

我只想用一些图形对象编写一个游戏,但我想用一些类来构建它。

整体布局应该是这样的:

MainClass -> new MainPanel(扩展 JPanel)->new StartWindow(扩展包含游戏循环的抽象 GameWindow)

这样我应该可以创建 StartWindow、Level1Window、Level2Window 等。 我的 StartWindow 现在应该为第一级绘制布局。 StartWindow 将创建其他对象(Player、Enemy 等),这些对象稍后将自己负责绘制。

所以我想创建类似“每个对象都有责任绘制自己”的东西

我希望我能弄清楚这应该如何工作。 问题是,我不知道如何委派这项任务。

我的代码现在看起来像这样:

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”包含主面板,所以我应该拥有在其面板上绘制所需的所有信息,我只是不知道该怎么做。

编辑: 最低限度的例子:

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);  
}
}

【问题讨论】:

  • 只是一般性建议——少关注扩展 Swing 组件,多关注游戏逻辑结构的继承。您甚至可以(并且应该)创建不从 JComponent 继承但您提供绘画方法的可绘制逻辑结构,可能通过您自己的Drawable 接口继承。
  • 老实说,我认为我的继承结构结构良好。一个程序窗口,其中包含一个要在其上绘制的面板窗口。此面板窗口包含我可以创建和添加的级别窗口,但我认为合适。每个 LevelWindow 都继承自我的游戏循环窗口。
  • 那么您最具体的问题是什么?您能否创建一个minimal reproducible example 程序,我们可以将其复制并粘贴到我们的 IDE 中,无需更改即可运行,无需外部依赖项,并以具体方式展示您的问题?
  • 明确的问题是:如何在我的 JPanel 上的 StartWindow 类中绘图。

标签: java swing oop inheritance jpanel


【解决方案1】:

我会在你的主绘图 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&lt;Tickable&gt; 由主模型保存,并且每次游戏循环滴答作响时,它都会遍历列表,对列表中的每个项目调用 tick(...)

【讨论】:

  • 非常感谢您,我试图了解您在做什么。你能解释一下gameloop参考是什么意思吗?你可以修改你的代码,这样我就可以理解你试图通过参考说的话吗?
  • @Hunselfunsel:也许是一个更好的主意——请参阅编辑。
【解决方案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();
}

【讨论】:

  • 这看起来像是危险的代码——当JVM真的应该这样做时直接调用paintComponent,并且在这个过程中忽略了组件边框和子组件的绘制。你能解释一下为什么推荐这个吗?
  • StartWindow的paintComponent方法与JComponent类的paintComponent方法无关。我认为他尝试将 StartWindow 用作精灵。
猜你喜欢
  • 1970-01-01
  • 2015-03-04
  • 2016-08-27
  • 2013-07-08
  • 2022-01-22
  • 1970-01-01
  • 1970-01-01
  • 2012-07-28
  • 1970-01-01
相关资源
最近更新 更多