我如何将 OpenGl 显示附加到 JFrame,以便在我关闭 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);
}
}
在执行可运行程序之前,我将 opengl 显示附加到 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 并修复上面的错误?
最佳答案
看起来您在“主”线程中启动了 Display(它为主线程提供了当前的 OpenGL 上下文),但您正试图从另一个线程中销毁显示,在本例中为 Event Dispatch线程(美国东部时间)。 但是,在给定时间只有一个线程可以拥有当前 OpenGL 上下文。
虽然可以更改哪个线程具有当前上下文,但我认为这不是您想要在此处执行的操作。
然后,我们在这里要做的是在我们创建它的同一线程(具有当前 OpenGL 上下文的线程)上销毁显示。一个approach我看到的是使用在EDT上运行的Canvas
的addNotify(
)和removeNotify()
方法来设置在 OpenGL 线程上检查以确定何时销毁显示的标志。
此外,问题提到了有关设置显示大小的问题。由于 setSize() 和 LayoutManager 的工作方式,您的 JFrame 显示大小和显示大小未设置为您想要的。请参阅Java tutorials和文档以获取详细信息。在下面的例子中,我使用了一种方法来解决这个问题。
所以这里有一个例子试图贴近问题中发布的代码的意图:
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 测试的,因为这似乎是问题最初发布时可用的最新版本。
关于java - 如何将 opengl 显示附加到 JFrame 并正确处理它?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/26199534/