当前位置: 首页 > 知识库问答 >
问题:

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

公冶弘壮
2023-03-14

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

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

}

在我进行可运行之前,我已经将开放显示器连接到JFrame。但是在添加可运行的显示器后,显示屏现在显示的尺寸与我的屏幕尺寸相同。我已尝试重新排列

canvas.setSize();

frame.setSize();

但是没有什么变化,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

这让我想到我的

Display.destroy();

我猜这是在告诉我我没有正确处理显示器?有人能帮我将opengl显示器连接到JFrame并修复上面的错误吗?

共有1个答案

水铭晨
2023-03-14

看起来您在“主”线程中启动了显示(它为主线程提供了当前的 OpenGL 上下文),但您正在尝试从其他线程(在本例中为事件调度线程 (EDT))中销毁显示。但是,在给定时间,只有一个线程可以具有当前的 OpenGL 上下文。

尽管可以改变哪个线程拥有当前上下文,但我不认为这是您想要做的。

我们在这里要做的是在我们创建它的同一线程(具有当前OpenGL上下文的线程)上销毁显示。我看到的一种方法是使用CanvasaddNotify()和removeNotify()方法,这些方法在EDT上运行,设置一个在OpenGL线程上检查的标志,以确定何时销毁显示。

此外,该问题还提到了有关设置显示器尺寸的问题。您的 JFrame 显示大小和显示大小未设置为所需的大小,因为 setSize() 和布局管理器的工作方式。有关详细信息,请参阅 Java 教程和文档。在下面的示例中,我使用了一种方法来解决此问题。

下面是一个试图接近问题中代码意图的示例:

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 进行测试的,因为该版本似乎是最初发布问题时可用的最新版本。

 类似资料:
  • 在你说这是转发之前,我必须说我已经试过阅读其他帖子,所以请继续阅读。 在text View中显示链接的基本方法可以通过下一种方式完成: 还有绳子。xml文件可能包含: 然而,我们可能希望捕获点击链接的事件,并自行处理。不仅如此,链接可能不需要是真正的url。 许多帖子存在,以显示如何做到这一点,但没有一个,我试图处理好。 有些应用程序允许在应用程序上处理意图,这相当麻烦,可能意味着其他应用程序也可

  • 我有一个,我需要在其中显示孟加拉语文本,例如: বাংলাদেশ 但是我只能看到长方形的盒子。我怎么才能正确地展示孟加拉文字呢?

  • 问题内容: 我已经开发了一个小应用程序来跟踪我的日常工作活动,该工具包含两个类: 执行者 UIProgress 我的目标是创建一个ProgressBar来更新执行状态,使用的逻辑如下所示, 根据Executor类中定义的executeTask(),我创建了UIProgress对象。 UIProgress类扩展了JFrame。创建一个面板,其中包含带有一个图像的标签和进度条。我已经在此类中定义了一个

  • 我开发了一个小应用程序来跟踪我的日常工作活动,该工具包含两个类: 遗嘱执行人 我的目标是创建一个更新执行状态的ProgressBar,下面给出了使用的逻辑, 从Exector类中定义的执行任务()中,我创建了UIProgress对象。 UIProgress类扩展了JFrame。创建一个包含带有一个图像和进度条的标签的面板。我在这个类中定义了一个方法updateProgress,它设置了进度条的值。

  • 如何将json结果正确附加到select选项, json数据样本 Ajax代码: html代码: 我已经设置为我的php文件

  • 我正在尝试从CloudWatch启动StepFunction。当事件源是一个时间表时,这就像一个魅力。但是,当我尝试创建事件模式来观看相应的SNS主题时,CloudWatch看不到它的发布。我尝试了两种默认模式: 并使用arn: 在这两种情况下,当我发布到主题时都没有发生任何事情。我做错了什么?更新:不幸的是,我不明白“事件模式”规则是干什么的,它在其他情况下不起作用——即使事件是从lambda手