如何将opengl display附加到JFrame并正确处理? [英] How to attach opengl display to a JFrame and dispose of it properly?

查看:85
本文介绍了如何将opengl display附加到JFrame并正确处理?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

如何将OpenGl显示器附加到JFrame上,以便在我关闭JFrame时会破坏该显示器?到目前为止,这是我的代码:

How can i attach the OpenGl display to a JFrame and so that when i close the JFrame is destroys the display? 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);
    }

}

在我进行可运行操作之前,我已将opengl显示附加到JFrame.但是,在添加了可运行对象之后,现在显示的屏幕尺寸与我的屏幕尺寸相同.我尝试重新排列

I had the opengl display attach to the JFrame before i did the runnable. But after adding the runnable the display now shows up the same size as my screen size. I have tried rearranging the

canvas.setSize();

frame.setSize();

但是没有任何变化,opengl显示仍然是相同的大小,当我尝试先关闭JFrame而不是先关闭显示时,我得到此错误:

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:

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

这使我指向了我的

Display.destroy();

哪个即时通讯正在告诉我我没有正确放置显示器?谁能帮助我将opengl显示器附加到JFrame并解决上述错误?

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上下文)中启动了Display,但您正在尝试破坏该线程.从另一个线程显示,在这种情况下为事件调度线程(EDT). 但是,在给定的时间,只有一个线程可以拥有当前的OpenGL上下文.

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). However, only one thread can have the current OpenGL context at a given time.

尽管可以更改哪个线程具有当前上下文,但我认为这不是您要执行的操作.

Although it is possible to change which thread has the current context, I don't think that's what you want to do here.

然后,我们要在此处创建显示的同一线程(具有当前OpenGL上下文的线程)上破坏显示.我看到的方法是使用CanvasaddNotify()和在EDT上运行的>方法,以设置在OpenGL线程上检查的标志,以确定何时破坏显示.

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). 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.

此外,该问题提到了有关设置显示器尺寸的问题.由于setSize()和LayoutManager的工作方式,未将JFrame的显示大小和显示大小设置为所需的大小.有关详细信息,请参见 Java教程和文档.在下面的示例中,我使用一种方法来解决此问题.

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. Please see the Java tutorials and documentation for details. 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();
        }
    }

}

注意:本示例使用lwjgl 2.9.1版进行了测试,因为它似乎是最初发布问题时可用的最新版本.

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.

这篇关于如何将opengl display附加到JFrame并正确处理?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆