简体   繁体   English

如何将opengl显示附加到JFrame并正确处理?

[英]How to attach opengl display to a JFrame and dispose of it properly?

How can i attach the OpenGl display to a JFrame and so that when i close the JFrame is destroys the display? 如何将OpenGl显示附加到JFrame,以便当我关闭JFrame时会破坏显示? Here is my code so far: 到目前为止,这是我的代码:

package test.core;


import java.awt.BorderLayout;
import java.awt.Canvas;
import java.awt.Color;
import java.awt.Component;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.awt.event.WindowListener;
import java.util.logging.Level;
import java.util.logging.Logger;

import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JTextField;
import javax.swing.SwingUtilities;

import org.lwjgl.LWJGLException;
import org.lwjgl.opengl.Display;
import org.lwjgl.opengl.DisplayMode;
import org.lwjgl.opengl.GL11;

import static org.lwjgl.opengl.GL11.*;

public class Main {



    private static CreateCanvas canvas;
    private static CreateFrame frame;

    private static int width = 800;
    private static int height = 600;

    public static void main(String[] args) throws InterruptedException {
        startFrames();

        startDisplay();

    }

    public static void cleanUp() {
        Display.destroy();
    }

    private static void startDisplay() {
        try
        {
            Display.setParent(canvas);
            Display.create();
        }catch(LWJGLException ex)
        {
            Logger.getLogger(Main.class.getName()).log(Level.SEVERE, null, ex);
        }
    }
    private static void startFrames()
    {
        Runnable r = new Runnable(){
            @Override
            public void run(){
                frame = new CreateFrame();
                JButton button = new JButton("BUTTON");
                canvas = new CreateCanvas();
                JPanel panel = frame.panel;

                panel.add(canvas);
                panel.add(button);
                frame.add(panel);

                canvas.setSize(300, 300);
                frame.setSize(width, height);

                frame.setDefaultCloseOperation(JFrame.DO_NOTHING_ON_CLOSE);

                WindowListener listen = new WindowAdapter(){
                    @Override
                    public void windowClosing(WindowEvent we){
                        int result = JOptionPane.showConfirmDialog(frame, "Do you want to quit the Application?");
                        if(result == JOptionPane.OK_OPTION){
                            frame.setVisible(false);
                            cleanUp();
                            frame.dispose();
                        }
                    }
                };

                frame.addWindowListener(listen);


                frame.setVisible(true);
            }

        };
        SwingUtilities.invokeLater(r);
    }

}

I had the opengl display attach to the JFrame before i did the runnable. 在我执行runnable之前,我将opengl显示附加到JFrame。 But after adding the runnable the display now shows up the same size as my screen size. 但是在添加了runnable后,显示屏现在显示的尺寸与我的屏幕尺寸相同。 I have tried rearranging the 我试过重新排列

canvas.setSize();

and the

frame.setSize();

but nothing changes the opengl display is still the same size and when i try to close the JFrame first rather then close the display first i get this error: 但没有任何改变opengl显示仍然是相同的大小,当我尝试先关闭JFrame而不是先关闭显示我得到这个错误:

Exception in thread "AWT-EventQueue-0" java.lang.IllegalStateException: From thread Thread[AWT-EventQueue-0,6,main]: Thread[main,5,main] already has the context current

which points me to my 这指向我的

Display.destroy();

which im guessing is telling me that i am not properly disposing the display? 我猜是在告诉我,我没有正确处理显示器? Can anyone help me attach the opengl display to the JFrame and fix the error above? 任何人都可以帮助我将opengl显示附加到JFrame并修复上面的错误?

It appears that you started the Display in the "main" thread (which gives the main thread the current OpenGL context), but you're trying to destroy the display from a different thread, which in this case is the Event Dispatch Thread (EDT). 看来你在“主”线程中启动了显示(它为主线程提供了当前的OpenGL上下文),但你试图从另一个线程中销毁显示,在这种情况下是事件调度线程(EDT) )。 However, only one thread can have the current OpenGL context at a given time. 但是,在给定时间只有一个线程可以拥有当前的OpenGL上下文。

Although it is possible to change which thread has the current context, I don't think that's what you want to do here. 虽然可以更改哪个线程具有当前上下文,但我不认为这是您想要在此处执行的操作。

What we want to do here then is to destroy the display on the same thread that we created it on (the thread with the current OpenGL context). 我们在这里要做的是在我们创建它的同一个线程(具有当前OpenGL上下文的线程)上销毁显示。 An approach I've seen is to use the Canvas 's addNotify( ) and removeNotify() methods, which are run on the EDT, to set a flag that is checked on the OpenGL thread to determine when to destroy the display. 我看到的一种方法是使用CanvasaddNotify( )和removeNotify()方法,这些方法在EDT上运行,设置一个在OpenGL线程上检查的标志,以确定何时销毁显示。

Also, the question mentioned problems about setting the size of the display. 此外,该问题提到了关于设置显示器尺寸的问题。 Your JFrame display size and Display size were not being set to what you desired because of how setSize() and LayoutManager's work. 由于setSize()和LayoutManager的工作方式,您的JFrame显示大小和显示大小未设置为您所需的大小。 Please see the Java tutorials and documentation for details. 有关详细信息,请参阅Java教程和文档。 In the following example, I have use one approach to address this issue. 在以下示例中,我使用一种方法来解决此问题。

So here is an example trying to stay close to the intent of the code posted in the question: 所以这里有一个例子试图接近问题中发布的代码的意图:

import java.awt.BorderLayout;
import java.awt.Canvas;
import java.awt.Dimension;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;

import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JOptionPane;
import javax.swing.JPanel;

import org.lwjgl.LWJGLException;
import org.lwjgl.opengl.Display;
import org.lwjgl.opengl.DisplayMode;

public class LWJGLTester {

    private volatile boolean isRunning = false;

    /*
     * The question asker seemed to desire that the JFrame be 800x600 and
     * that the Display be 300x300.  Regardless of the desired sizes,
     * I think the important thing is to set the Canvas and Display to the same sizes.
     */
    private int frameWidth = 800;
    private int frameHeight = 600;
    private int displayWidth = 300;
    private int displayHeight = 300;

    private Thread glThread;

    public static void main(String[] args) {
        new LWJGLTester().runTester();
    }

    private void runTester() {
        final JFrame frame = new JFrame("LWJGL in Swing");
        frame.setSize(frameWidth, frameHeight);
        frame.setDefaultCloseOperation(JFrame.DO_NOTHING_ON_CLOSE);
        frame.addWindowListener(new WindowAdapter() {
            @Override
            public void windowClosing(WindowEvent we){
                int result = JOptionPane.showConfirmDialog(frame, "Do you want to quit the Application?");
                if(result == JOptionPane.OK_OPTION){
                    frame.setVisible(false);
                    frame.dispose(); //canvas's removeNotify() will be called
                }
            }
        });

        JPanel mainPanel = new JPanel(new BorderLayout());

        JButton button = new JButton("BUTTON");
        JPanel buttonPanel = new JPanel();
        buttonPanel.add(button);
        mainPanel.add(buttonPanel, BorderLayout.NORTH);

        Canvas canvas = new Canvas() {
            @Override
            public void addNotify() {
                super.addNotify();
                startGL();
            }

            @Override
            public void removeNotify() {
                stopGL();
                super.removeNotify();
            }
        };
        canvas.setPreferredSize(new Dimension(displayWidth, displayHeight));
        canvas.setIgnoreRepaint(true);

        try {
            Display.setParent(canvas);
        } catch (LWJGLException e) {
            //handle exception
            e.printStackTrace();
        }
        JPanel canvasPanel = new JPanel();
        canvasPanel.add(canvas);
        mainPanel.add(canvasPanel, BorderLayout.SOUTH);

        frame.getContentPane().add(mainPanel);

        //frame.pack();
        frame.setVisible(true);
    }

    private void startGL() {
        glThread = new Thread(new Runnable() {
            @Override
            public void run() {
                isRunning = true;
                try {
                    Display.setDisplayMode(new DisplayMode(displayWidth, displayHeight));
                    Display.create();
                } catch (LWJGLException e) {
                    //handle exception
                    e.printStackTrace();
                }

                // init OpenGL here

                while(isRunning) {
                    // render OpenGL here
                    Display.update();
                }

                Display.destroy();
            }
        }, "LWJGL Thread");

        glThread.start();
    }

    private void stopGL() {
        isRunning = false;
        try {
            glThread.join();
        } catch (InterruptedException e) {
            //handle exception
            e.printStackTrace();
        }
    }

}

Note: This is example was tested using lwjgl version 2.9.1, since that seemed to be the latest version available at the time the question was originally posted. 注意:这个示例是使用lwjgl版本2.9.1测试的,因为它似乎是最初发布问题时可用的最新版本。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM