Shared GLJPanel for a JTabbedPane

Hi,

I have a Swing application with a JTabbedPane. Each tab shows a document that needs a GLJPanel. Since they share the same textures, I want to use only one GLJPanel for all tabs.

There would be two ways to do this:

  • Just use the same component for all tab pages (but seems to be impossible in Swing? ??? )
  • Add the GLJPanel to the current page when opened (ChangeListener).

The second idea works - but init() is called again and I have to reload all textures - this is slow.
Does anybody have an idea how I could do it? Is there perhaps a way to avoid the reinitialization of the GLJPanel?
I also thought about writing my own version of a tabbed pane…

Thanks :slight_smile:

Andi

I already found a “dirty” workaround, if we can not find a solution.

The JTabbedPane is on the top and is only as high as its buttons. Unfortunately this isn’t possible in swing (its content pane seems to be at least around 20 px high, even if all child panels want to have a height of 0 px), but with this workaround I can place the JTabbedPane at the north side of a BorderLayout and the GLJPanel at the center of the BorderLayout:

tabPanel.setPreferredSize(new Dimension(0,
  tabPanel.getUI().getTabBounds(tabPanel, 0).height);

Now the JTabbedPane is forced to have only the height of its buttons (should work for all look and feels), at it looks as if the GLJPanel belongs to the tabs.

A better solution would be great, but it’s a temporary solution.

We’ve run into similar issues with an application we’re building in-house.

First, you can work around the repeated calls to GLEventListener.init() by causing your GLJPanel to share textures and display lists with a 1x1 GLPbuffer that you create up front. This way, even though init() is called multiple times, you don’t need to reload the textures, but can reuse the texture IDs since the presence of the pbuffer’s OpenGL context will prevent the textures from being deleted by OpenGL.

You can also work around the repeated calls to GLJPanel.addNotify() and removeNotify(). Basically, you can subclass the GLJPanel and override these methods. You can consider the first call to addNotify() to have created the GLJPanel and ignore subsequent calls to addNotify(). You can add a method like “destroy()” to your GLJPanel subclass which simply sets a “destroyed” flag and calls removeNotify(). Finally, you can override removeNotify() and check the destroyed flag, only calling super.removeNotify() if the panel has been destroyed by your application. Here’s some code:


    static class PersistentGLJPanel extends GLJPanel {
        private boolean created;
        private boolean destroyed;

        public PersistentGLJPanel(GLCapabilities capabilities,
                                    GLCapabilitiesChooser chooser,
                                    GLContext shareWith) {
            super(capabilities, chooser, shareWith);
        }

        public void addNotify() {
            if (!created) {
                created = true;
                super.addNotify();
            }
        }

        public void removeNotify() {
            if (destroyed) {
                super.removeNotify();
            }
        }
        
        public void destroy() {
            destroyed = true;
            removeNotify();
        }
    }

I tried your second solution and it works great - fantastic!
Thank you very much for your excellent answers all the time :smiley:

Hi,
I have the same situation and as Ken says I use the first option. My class MyCanvas extends GLJPanel and uses an static GLPBuffer that is initialized in the constructor. The context of the GLPbuffer is shared among all MyCanvas instances.

Also, every MyClass instance has a FPSAnimator. When I change between tabs I start or stop the animator depending on the visible tab (this improves the performance).