Java 为什么我的画布在添加到JFrame后无法绘制?

Java 为什么我的画布在添加到JFrame后无法绘制?,java,swing,lwjgl,Java,Swing,Lwjgl,我正在编写一个小游戏,它使用画布实例进行绘制(如果熟悉,我使用游戏库LWJGL)。 现在我已经为我的游戏创建了一个主菜单,它由一个JPanel组成,然后在游戏开始时添加到我的主游戏JFrame中 Canvas canvas = new Canvas(); JFrame frame = new JFrame("Puzzler"); this.canvas = canvas; this.jframe = frame; canvas.setIgnoreRepaint(true); frame.setS

我正在编写一个小游戏,它使用画布实例进行绘制(如果熟悉,我使用游戏库LWJGL)。 现在我已经为我的游戏创建了一个主菜单,它由一个JPanel组成,然后在游戏开始时添加到我的主游戏JFrame中

Canvas canvas = new Canvas();
JFrame frame = new JFrame("Puzzler");
this.canvas = canvas;
this.jframe = frame;
canvas.setIgnoreRepaint(true);
frame.setSize(640, 480);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setVisible(true);
接下来,我创建主菜单:

this.mainMenuPanel = new MainMenuPanel(this.main);
this.jframe.setSize(500, 170);
this.jframe.getContentPane().add(mainMenuPanel);
this.jframe.validate();
最后,当主菜单想要开始游戏时,我尝试用画布实例替换主菜单的JPanel:

this.jframe.setVisible(false);
this.jframe.invalidate();
this.jframe.removeAll();
this.jframe.getContentPane().add(canvas);
this.jframe.setVisible(true);
this.jframe.pack();
this.jframe.setSize(640, 480);
this.jframe.validate();
当最后一段代码运行时,对LWJGL的Display.create()的调用将返回一个错误,即画布不可绘制。 我已经尝试了很多组合(比如添加一个JPanel作为画布的容器,运气不好),并且经常弄乱validate()和repaint()调用的顺序,因为这在swing中有时会有所帮助。有人知道这里有什么问题吗

编辑
我已经解决了这个问题。问题是java的事件处理线程在运行主循环时陷入困境,因为我在主线程上调用了run(),而不是start()。我真傻P

不要混合swing和awt组件。帆布是awt。使用JPanel重写

paintComponent Graphics g)
方法


除了不混合规则之外,我猜在纯awt上下文中也会出现类似的异常-来自LWJGL:

现在我们有了基本的模板,我们需要粘贴LWJGL本机 在上面显示。为此,我们只需使用Display.setParent(Canvas) 方法。但是,在创建显示之前,我们需要确保 画布已准备好绘制。为了确保这一点,我们将使用 awt画布的addNotify()方法来告诉我们画布何时启动 准备好了,我们可以创建显示。同样,我们将使用 removeNotify()通知我们画布即将被销毁 我们应该清理并关闭本机显示器

编辑

(仍然没有IDE在手,只是从我的头顶;-)

事实上,我不太明白你在做什么,没有任何必要。首先,我将保持它的简单性,并与教程中所示的完全相同:

 display_parent = new Canvas() {
    public final void addNotify() {
       super.addNotify();
       startLWJGL();
    }
    public final void removeNotify() {
      stopLWJGL();
      super.removeNotify();
    }
 };
 frame.add(display.parent);
另外,请确保所有更改都发生在EDT上-这可能是真正的问题,因为不知道在这些方法中显示的实际功能:

 public void gameLoop() {
     while(running) {
         SwingUtilities.invokeLater(new Runnable() {
             public void run() {
                 Display.sync(60);
                 Display.update();
             }
         });
    }

    Display.destroy();
 }      
编辑2

只需在JFrame中运行示例(在上面引用的教程中),不更改现有代码,只需添加一个main:

    public static void main(String[] args) {
        final JFrame frame = new JFrame("Gears AWT");

        final JPanel intro = new JPanel();
        Action action = new AbstractAction("Start Gears") {

            @Override
            public void actionPerformed(ActionEvent e) {
                GearsApplet gears = new GearsApplet();
                gears.init();
                frame.remove(intro);
                frame.add(gears);
                frame.getRootPane().revalidate();
            }
        };
        JButton button = new JButton(action);
        intro.add(button);
        frame.add(intro); //.display_parent);
        frame.setSize(200, 200);
        frame.setVisible(true);
    }

感觉很好(在一级近似情况下,怀疑有一些魔鬼隐藏在较暗的线程壁龛中-因为我们不在EDT上(最有可能)),齿轮正在运行,团队可以旋转

事实上,我没有。我在游戏结束后添加了主菜单;它运行起来就像一个没有swing代码的符咒。但是,一旦我添加了包含主菜单的JPanel,它就会抛出错误。@Bartvbl为我提供了正确的服务,可以自由猜测:-)嗯。。您是否尝试覆盖addnotify?随机思考(我的上网本不是一个合理的编程环境:在我的脑海里有一点信息,在当前的JDK(>1.6u10)中混合更容易)嗯。我必须说,我对小程序不是特别熟悉;我只是为桌面编写一些东西。虽然我确实记得小程序有一些不同的绘图和一般工作方式。也许addNotify()就是其中之一?或者它也适用于常规应用程序吗?等等……我只是用“删除”替换了“removeAll()”(mainMenuJPanel)”。现在画布显示,在画布上绘制的游戏也显示出来。但窗口本身完全冻结。它不会调整大小,只按窗口的原始大小绘制画布:/@klweopatra:the remove()这个方法是为了摆脱占据主菜单的JPanel。精细地显示游戏和创建LWJGL的openGL上下文是没有问题的。问题是,一旦我将JPanel添加到等式中,它就会崩溃;窗口的内容只是挂起,而窗口的关闭按钮完全不起作用。嗯。这可能确实是它不起作用的原因规矩点。我去看看。应该不会有太大问题,因为jdk 6u12(虽然没有测试)不必担心sscce,教程页面似乎有一个:-)@kleopatra:我的存储库在这里:git@github.com:bartvbl/CoopPuzzler.git。感兴趣的文件是client.clientWindow和client.gui.MainMenuPanel(及其相关的MainMenuView).ClientWindow处理窗口内容,MainMenuPanel是组成主菜单的JPanel。我现在确实设法让画布调整大小,但由于某种奇怪的原因,LWJGL检索到画布大小时(0,0),崩溃了。我并不太喜欢浏览大量文件;-)让我们继续学习教程中的示例-它在JFrame中运行良好(请参见edit2)。好的,将main更改为模仿,将intro(主菜单)面板替换为canvas。这就是我愿意走多远,希望它能帮助你在代码中找到问题:-)@kleopatra:我已经解决了问题。我在我创建的主线程上使用了run()方法,这使得JavaAWT事件处理线程一直在等待主循环完成。将其更改为start(),结果是一个完美的游戏。再次感谢您的帮助!:)