Resize behaviour

Firstly: WOW. I’ve been using GL4Java for about 2 years now, and so I can really appreciate what a fantastic, literally fantastic job you’ve all done putting this together. Excellent cross platform work, and very simple for installation - and I love the debugging of GL errors made easy through the GLExceptions. Well done.

Now for my problem. I’m trying to get a GLCanvas to behave properly when added with other siblings to a parent. I’m finding that as I resize my window, the GLCanvas consumes more and more space, eventually (often) occupying all the available area.

In the following code, I add a label and a GLCanvas, both of which are told to share the remaining space equally. However as I resize the frame containing them both, the GLCanvas consumes more and more space on each resize. Eventually the GLCanvas actually occupies all of the canvas area, and we cannot see the label at all. (A quick maximize then restore operation should do it for you).


import net.java.games.jogl.*;
import java.awt.*;
import javax.swing.*;

public class Test
{
    public static void main(String[] args) {
        JFrame f = new JFrame();
        f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        JPanel c = new JPanel();
        c.setPreferredSize(new Dimension(400,400));
        f.getContentPane().add(c);
        c.setLayout(new GridBagLayout());
        GridBagConstraints gbc = new GridBagConstraints();
        gbc.gridwidth = GridBagConstraints.REMAINDER;
        gbc.gridheight = 1;
        gbc.weightx = gbc.weighty = 1;
        gbc.fill = GridBagConstraints.BOTH;

        JPanel p = new JPanel();
        p.setBackground(Color.RED);
        p.add(new JLabel("don't squeeze me!"));
        c.add(p,gbc);
        /*
        JPanel p2 = new JPanel();
        p2.setBackground(Color.BLUE);
        p2.add(new JLabel("me neither!"));
        c.add(p2,gbc);
        */
        GLCanvas glc = GLDrawableFactory.getFactory().createGLCanvas(
            new GLCapabilities());
        glc.addGLEventListener(
            new GLEventListener() {
                public void init(GLDrawable drawable) {}
                public void display(GLDrawable drawable) {
                    GL gl = drawable.getGL();
                    gl.glClear(GL.GL_COLOR_BUFFER_BIT);
                }
                public void displayChanged(GLDrawable d,boolean b,boolean c){}
                public void reshape(GLDrawable d,int a,int b,int c,int e){}
            }
        );
        c.add(glc,gbc);

        f.pack();
        f.setVisible(true);
    }
}

Some test code (overriding the preferred size operation by using an intermediate class) shows me that what’s happening is that the GLCanvas’ preferred size is continuously increasing each time the GLCanvas is resized. I can therefore avoid the problem by just returning a new Dimension(0,0). But tell me, am I missing something? Is there a good reason for this behaviour?

This is a known bug in the GLCanvas but I’m not sure of the correct solution. See Issue 135 in the JOGL Issue Tracker. If you could come up with a patch you can guarantee works in all cases then I’ll be happy to integrate it. I don’t know all of the semantics of setMinimumSize / setPreferredSize / setMaximumSize and why they behave differently for lightweight and heavyweight widgets.

I’ve seen some people set up a JPanel with a minimum size of (0, 0) and add their GLCanvas to that as a workaround.

Glad the library is (mostly) working for you.

I’ve solved this in a few cases by adding the GLPanel to a JPanel and then use the JPanel inside the other controls :slight_smile:

I’ve investigated this issue further and believe there is no good solution. Simply overriding getPreferredSize() on GLCanvas and having it default to (0, 0) fixes your test case and some others but breaks most of the JOGL demos, which use a different LayoutManager. As far as I can tell this is a fundamental difference between how heavyweight and lightweight widgets interact with their LayoutManagers. The best and most portable solution is to add your GLCanvas to a JPanel and set the JPanel’s preferred size to (0, 0). See JOGL Issue 135 for a more detailed writeup. Here is a version of your test case which behaves properly.


 import net.java.games.jogl.*;
import java.awt.*;
import javax.swing.*;
 
public class Test
{
    public static void main(String[] args) {
   JFrame f = new JFrame();
   f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
   JPanel c = new JPanel();
   c.setPreferredSize(new Dimension(400,400));
   f.getContentPane().add(c);
   c.setLayout(new GridBagLayout());
   GridBagConstraints gbc = new GridBagConstraints();
   gbc.gridwidth = GridBagConstraints.REMAINDER;
   gbc.gridheight = 1;
   gbc.weightx = gbc.weighty = 1;
   gbc.fill = GridBagConstraints.BOTH;
 
   JPanel p = new JPanel();
   p.setBackground(Color.RED);
   p.add(new JLabel("don't squeeze me!"));
   c.add(p,gbc);
   /*
   JPanel p2 = new JPanel();
   p2.setBackground(Color.BLUE);
   p2.add(new JLabel("me neither!"));
   c.add(p2,gbc);
   */
   GLCanvas glc = GLDrawableFactory.getFactory().createGLCanvas(
  new GLCapabilities());
   glc.addGLEventListener(
  new GLEventListener() {
      public void init(GLDrawable drawable) {}
      public void display(GLDrawable drawable) {
     GL gl = drawable.getGL();
     gl.glClear(GL.GL_COLOR_BUFFER_BIT);
      }
      public void displayChanged(GLDrawable d,boolean b,boolean c){}
      public void reshape(GLDrawable d,int a,int b,int c,int e){}
  }
   );
   // Old code
   //   c.add(glc,gbc);

   // Workaround
   JPanel cont = new JPanel();
   cont.setLayout(new BorderLayout());
   cont.add(glc, BorderLayout.CENTER);
   cont.setPreferredSize(new Dimension(0, 0));
   c.add(cont, gbc);
 
   f.pack();
   f.setVisible(true);
    }
} 

Thank you for the proper follow up, having looked at the code myself I agree with you, and for now I am perfectly happy with the fix you suggested - that’s exactly what I’m doing.

Thanks.

Hugo