I dont really agree. OpenGL is just a general purpose 'graphics library'. There are many applications that would utilise a "paint when required" in a good way. A Timer is just a fixed update rate what is common in games.
I also found the problem not really within mixing heavy and lightweight components but simply in the direct call to canvas.update. Check this out, I wrote more comments about it there :
//~--- non-JDK imports --------------------------------------------------------
import org.lwjgl.LWJGLException;
import org.lwjgl.opengl.AWTGLCanvas;
import org.lwjgl.opengl.PixelFormat;
import static org.lwjgl.opengl.GL11.*;
//~--- JDK imports ------------------------------------------------------------
import java.awt.Color;
import java.awt.Dimension;
import java.awt.event.ComponentAdapter;
import java.awt.event.ComponentEvent;
import java.awt.FlowLayout;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.nio.file.Paths;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;
import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JSplitPane;
import javax.swing.SwingUtilities;
//~--- classes ----------------------------------------------------------------
/**
*/
public class CanvasTest implements Runnable
{
//~--- fields ---------------------------------------------------------------
private AWTGLCanvas canvas;
//~--- methods --------------------------------------------------------------
/**
*
* @param args String[]
*/
public static void main(String[] args)
{
System.setProperty("org.lwjgl.librarypath", Paths.get("bin", "windows").toAbsolutePath().toString()); // if natives are at bin/windows
//
SwingUtilities.invokeLater(new CanvasTest()); // move all swing init calls into EDT. just to be sure.
}
/**
*/
@Override
public void run()
{
try
{
canvas = new AWTGLCanvas(new PixelFormat(8, 8, 0, 4))
{
@Override
public void initGL()
{
glDisable(GL_DEPTH_TEST);
glDisable(GL_CULL_FACE);
System.out.println("gl init called. " + Thread.currentThread().getId() + " " + Thread.currentThread().getName());
}
@Override
public void paintGL()
{
try
{
glViewport(0, 0, getWidth(), getHeight());
glColor3d(Math.random() * .5 + .25, Math.random() * .5 + .25, Math.random() * .5 + .25); // randomise color so we can see the updates.
glBegin(GL_QUADS);
glVertex2f(-1, -1);
glVertex2f(1, -1);
glVertex2f(1, 1);
glVertex2f(-1, 1);
glEnd();
glColor3f(1f, 0, 1f);
glLineWidth(3f);
glBegin(GL_LINE_STRIP);
glVertex2f(-1, -1);
glVertex2f(1, -1);
glVertex2f(1, 1);
glVertex2f(-1, 1);
glEnd();
glFinish();
swapBuffers();
System.out.println("gl buffers swapped. " + Thread.currentThread().getId() + " " + Thread.currentThread().getName());
}
catch(LWJGLException ex) {}
}
};
canvas.setIgnoreRepaint(false); // use true if you want to block all paint calls to the canvas.
canvas.setPreferredSize(new Dimension(100, 100)); // moved from inside initGL() so its called once canvas is displayed by AWT
canvas.setSize(new Dimension(100, 100));
canvas.setBackground(Color.green); // if you see green on the canvas, it means the canvas shape is not updated correctly. I am not sure how to fix it.
}
catch(Exception e)
{
e.printStackTrace(System.err);
}
JPanel panel_top = new JPanel(new FlowLayout(FlowLayout.CENTER, 0, 0));
JPanel panel_bottom = new JPanel(new FlowLayout(FlowLayout.CENTER, 0, 0));
panel_top.setPreferredSize(new Dimension(200, 300));
panel_bottom.setPreferredSize(new Dimension(200, 300));
panel_top.setBackground(Color.lightGray);
panel_bottom.setBackground(Color.lightGray);
//
JPanel dummy = new JPanel(); // just a red square
dummy.setBackground(Color.red);
dummy.setPreferredSize(new Dimension(100, 100));
dummy.setSize(new Dimension(100, 100));
//
panel_top.add(dummy);
panel_bottom.add(canvas);
JScrollPane scrollpane_top = new JScrollPane(panel_top);
JScrollPane scrollpane_bottom = new JScrollPane(panel_bottom);
JSplitPane splitpane = new JSplitPane(JSplitPane.VERTICAL_SPLIT);
splitpane.setPreferredSize(new Dimension(200, 300));
splitpane.setTopComponent(scrollpane_top);
splitpane.setBottomComponent(scrollpane_bottom);
splitpane.setContinuousLayout(true);
splitpane.setResizeWeight(0.5f);
//
scrollpane_bottom.getViewport().addChangeListener(new ChangeListener() // makes the canvas 'tight'. remove and watch the top pink line not beeing painted when scrolling up to top
{ // also the canvas doesn't 'stick out' when you scroll down
@Override
public void stateChanged(ChangeEvent e)
{
((JComponent)e.getSource()).getParent().getParent().getParent().revalidate(); // not sure if this is the best way but it works. maybe there is a better. I gues I try to get to the frame.
}
});
//
splitpane.addPropertyChangeListener("dividerLocation", new PropertyChangeListener() // makes the canvas NOT overlap bottom scrollbar when moving the divider to bottom.
{
@Override
public void propertyChange(PropertyChangeEvent e)
{
((JComponent)e.getSource()).getParent().revalidate();
}
});
JFrame frame = new JFrame();
frame.addComponentListener(new ComponentAdapter()
{
@Override
public void componentResized(ComponentEvent e)
{
// ???
}
});
//
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setLocation(400, 400);
frame.add(splitpane);
frame.pack();
frame.setVisible(true);
// one thing stay ugly; if you resize the frame you see the canvas overlapping components badly.
// on the other hand, watch how good the canvas position is updated, compared to the upper red JPanel.
/* */
// in case canvas is not painted by AWT
if(canvas.getIgnoreRepaint())
{
Thread glUpdater = new Thread(new Runnable()
{
@Override
public void run()
{
while(true)
{
try
{
canvas.paint(null);
Thread.sleep(250); // one could probably insert a ReentrantLock.Condition here and trigger updates properly from inside the EDT.
}
catch(InterruptedException ex) {}
}
}
}, "gl-updater");
glUpdater.setDaemon(true);
glUpdater.start();
}
}
}
It works quiet ok but there are still things to be done correctly. I think there is a way to interleave the GL with the AWT paints to get the canvas beeing always rendered correctly.
bas
*edit*
before it gets confusing, I had issues with LWJGL+Canvas before too. They disappeared once I updated JVM to > JDK 1.7.0_5 and LWJGL 2.9.0.