How to connect opengl display to JFrame and dispose of it properly?

How can I attach an OpenGl display to a JFrame, and so when I close the JFrame, it destroys the display? Here is my code:

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 an opengl display attached to a JFrame before I rannable. But after adding a runnable, the display now shows the same size as the screen size. I tried to rearrange

 canvas.setSize(); 

and

 frame.setSize(); 

but nothing changes the opengl display is still the same size, and when I try to close the JFrame first and then close the display, I get this error first:

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

of which I suspect, tells me that I am not disposing of the display correctly? Can someone help me attach an opengl mapping to a JFrame and fix the error above?

+5
source share
1 answer

It seems that you started displaying in the "main" thread (which gives the main thread the current OpenGL context), but you are trying to destroy the display from another thread, which in this case is the Theme (EDT) event dispatcher. 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 what you want to do here.

Here we want to destroy the display in the same stream in which we created it (the stream with the current OpenGL context). approach I have seen the use of methods of Canvas addNotify( ) and removeNotify() , which run on the EDT, select the check box that is checked in OpenGL stream to determine when to destroy the display.

In addition, questions about setting the display size were mentioned to the question. The size of your JFrame display and the size of the display have not been adjusted as you would like, due to the way the setSize () and LayoutManager functions. See Java tutorials and documentation for more information. In the following example, I use one approach to solve this problem.

So, here is an example that is trying to get closer to the goal 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 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 example was tested using lwjgl version 2.9.1, as it seemed to be the latest version available at the time the question was originally published.

0
source

Source: https://habr.com/ru/post/1204032/


All Articles