我正在尝试为Game Engine Architecture中的类(class)构建一个简单的游戏基础。但是我的JFrame不会显示任何内容。

我的代码当前的结构如下:

Implementation.java(这是我正在创建的Engine软件包的任意实现)

public class Implementation {
    public static void main(String[] args){
        World w = new World("Hej", "M:\\workspace\\SP6\\pics\\tulips.jpg",1024,768);
    }
}

世界.java
public class World extends JFrame{
private static final long serialVersionUID = 1L;
private SpritePanel spritePanel;
private JPanel bottom;
private int width;
private int height;

public World(String windowCaption, String bgPath, int width, int height){
    super(windowCaption);

    spritePanel = new SpritePanel(bgPath);
    add(spritePanel, BorderLayout.CENTER);
    System.out.println(spritePanel);

    bottom = new JPanel();
    bottom.add(new JLabel("Hej"));
    add(bottom, BorderLayout.SOUTH);

    Dimension size = new Dimension(width,height);
    setSize(size);
    setLocationRelativeTo(null);
    setDefaultCloseOperation(EXIT_ON_CLOSE);

    pack();
    setVisible(true);

    validate();
    repaint();
}

SpritePanel.java
public class SpritePanel extends JPanel {
private static final long serialVersionUID = 1L;
private ImageIcon background;
private ArrayList<Sprite> sprites = new ArrayList<Sprite>();

public SpritePanel(String bgPath){
    background = new ImageIcon(bgPath);
    setLayout(null);
    Dimension size = new Dimension(background.getIconWidth(), background.getIconHeight());
    setPreferredSize(size);
    setMaximumSize(size);
    setMinimumSize(size);
}

@Override
protected void paintComponent(Graphics g){
    super.paintComponent(g);
    g.drawImage(background.getImage(), 0, 0, this);
    System.out.println("painted panel");
}
}

因此,目前的基本 Action 流程(据我所知):
  • 我在实现
  • 中创建一个新的World对象
  • 使用给定参数
  • 调用World-constructor
  • 设置了窗口标题(有效)
  • 我使用给定的bgPath
  • 创建一个新的SpritePanel对象
  • 调用SpritePanel构造函数并将ImageIcon设置为给定路径
  • 中存在的图像
  • 将SpritePanel添加到BorderLayout.CENTER的框架中
  • 我将新的JPanel添加到BorderLayout.CENTER中的框架
  • 我设置大小和内容
  • 我打包并将框架设置为可见
  • 我验证并重绘(repaint)

  • 事情是JPanel中的paintComponent方法,而SpritePanel似乎没有被调用。如您所见,我在paintComponent的SpritePanel中添加了System.out.println,并且该行从未执行。

    我注意到的另一件事是,程序包似乎知道组件在那里。因为如果我评论三行
    spritePanel = new SpritePanel(bgPath);
    add(spritePanel, BorderLayout.CENTER);
    System.out.println(spritePanel);
    

    运行程序时,Windows的大小减小为“底部” -JPanel的大小。我看不到添加到面板中的JLabel,但窗口大小就是它的大小。所以pack()方法似乎正在寻找组件的尺寸。

    如果我评论添加了底部面板的三行内容,则窗口大小将减小为无高度,并且宽度将从标准图标减小。

    我一直在尝试不同的方法来使其正常工作,但无济于事。我之前已经使用Swing进行了编程并制作了工作程序,但似乎在这里找不到问题。

    帮助非常感谢。

    最佳答案

    您的String路径可能有问题。但是,您应该做什么,而不是读取文件,而是应该读取URL,并从类路径中加载。在部署时,您会发现文件路径不起作用,因此最好将图像打包为embedded resource,然后将图像放在类路径中。这样做时我没有任何问题。这就是我所做的。

  • 将路径更改为相对于我的类(class)路径的路径
    World w = new World("Hej", "/resources/stackoverflow5.png", 1024, 768);
    
  • 从文件加载更改为从类路径的URL加载
    background = new ImageIcon(SpritePanel.class.getResource(bgPath));
    
  • 将图像放在类路径
  • 中的resources包中


    一切正常
    import java.awt.BorderLayout;
    import java.awt.Dimension;
    import java.awt.Graphics;
    import javax.swing.ImageIcon;
    import javax.swing.JFrame;
    import static javax.swing.JFrame.EXIT_ON_CLOSE;
    import javax.swing.JLabel;
    import javax.swing.JPanel;
    
    public class Implementation {
    
        public static void main(String[] args) {
            World w = new World("Hej", "/resources/stackoverflow5.png", 1024, 768);
        }
    }
    
    class World extends JFrame {
    
        private static final long serialVersionUID = 1L;
        private SpritePanel spritePanel;
        private JPanel bottom;
        private int width;
        private int height;
    
        public World(String windowCaption, String bgPath, int width, int height) {
            super(windowCaption);
    
            spritePanel = new SpritePanel(bgPath);
            add(spritePanel, BorderLayout.CENTER);
            System.out.println(spritePanel);
    
            bottom = new JPanel();
            bottom.add(new JLabel("Hej"));
            add(bottom, BorderLayout.SOUTH);
    
            Dimension size = new Dimension(width, height);
            setSize(size);
            setLocationRelativeTo(null);
            setDefaultCloseOperation(EXIT_ON_CLOSE);
    
            pack();
            setVisible(true);
    
            validate();
            repaint();
        }
    
        class SpritePanel extends JPanel {
    
            private static final long serialVersionUID = 1L;
            private ImageIcon background;
    //private ArrayList<Sprite> sprites = new ArrayList<Sprite>();
    
            public SpritePanel(String bgPath) {
                background = new ImageIcon(SpritePanel.class.getResource(bgPath));
                setLayout(null);
                Dimension size = new Dimension(background.getIconWidth(), background.getIconHeight());
                setPreferredSize(size);
                setMaximumSize(size);
                setMinimumSize(size);
            }
    
            @Override
            protected void paintComponent(Graphics g) {
                super.paintComponent(g);
                g.drawImage(background.getImage(), 0, 0, this);
                System.out.println("painted panel");
            }
        }
    }
    

    旁注
  • 无需setSize()。您已经pack()了。最好还是打包。
  • pack()放在setLocationRelativeTo()之前。如果之后使用pack(),您会发现您的相框将不在所需的位置。
  • 像这样从Event Dispatch Thread (EDT)运行您的Swing应用程序
    public static void main(String[] args){
        SwingUtilities.invokeLater(new Runnable(){
            @Override
            public void run() {
                new World("Hej", "/resources/stackoverflow5.png", 1024, 768);
            }
        });
    }
    
  • 如果要使框架填满整个屏幕,请不要设置大小。不同的机器具有不同的屏幕尺寸。而是使用setExtendedState(JFrame.MAXIMIZED_BOTH);
  • 同样,您的setSize()也将无法正常工作,因为之后您要调用pack()
  • 10-07 13:58