Compatibility with swing panels

I started down the path of normal swing panels around a JMECanvas,



Can you use JMEDesktop within JMECanvas. A lot of the code is using the AWTMouseInput with the provider of AWT



I tried to convert the JMESwingTest to use it, but got exceptions when it invoked the move action using swingutilities.invokeandwait


  • edit - the actual exception is thrown after performing update on the inputhandler

I believe someone already tried this. I remember I changed the popup factory to handle both, inner and outer swing, correctly. So it shouldn't be a general problem any more. Can't find it on the forum, though.



Regarding your specific problem please post more details if you want help with them.

Hi



Have knocked up a mod from the JMESwingTest



The desktop is put in its own class for clarity.



The area you may want to look at is in the init of the swing frame


package jmetest.util;

import java.awt.BorderLayout;
import java.awt.Canvas;
import java.awt.Color;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.Insets;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.ComponentAdapter;
import java.awt.event.ComponentEvent;
import java.awt.event.KeyListener;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.awt.event.MouseMotionListener;
import java.awt.event.MouseWheelListener;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;

import javax.swing.BorderFactory;
import javax.swing.JButton;
import javax.swing.JCheckBox;
import javax.swing.JColorChooser;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTree;
import javax.swing.UIManager;

import com.jme.bounding.BoundingBox;
import com.jme.image.Texture;
import com.jme.input.InputHandler;
import com.jme.input.InputSystem;
import com.jme.input.KeyInput;
import com.jme.input.KeyboardLookHandler;
import com.jme.input.MouseInput;
import com.jme.math.FastMath;
import com.jme.math.Quaternion;
import com.jme.math.Vector3f;
import com.jme.renderer.Renderer;
import com.jme.scene.shape.Box;
import com.jme.scene.state.TextureState;
import com.jme.system.DisplaySystem;
import com.jme.util.TextureManager;
import com.jme.util.Timer;
import com.jmex.awt.JMECanvas;
import com.jmex.awt.JMECanvasImplementor;
import com.jmex.awt.SimpleCanvasImpl;
import com.jmex.awt.input.AWTKeyInput;
import com.jmex.awt.input.AWTMouseInput;

public class JMESwingDesktopTest {

    int width = 640, height = 480;
    InputHandler input;
    // Swing frame
    private SwingFrame frame;

    public JMESwingDesktopTest() {
        frame = new SwingFrame();
        // center the frame
        frame.setLocationRelativeTo(null);
        // show frame
        frame.setVisible(true);
    }

    /**
     * Main Entry point...
     *
     * @param args
     *            String[]
     */
    public static void main(String[] args) {

        try {
            UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
        } catch (Exception e) {
            e.printStackTrace();
        }
        new JMESwingDesktopTest();
    }

    // **************** SWING FRAME ****************

    // Our custom Swing frame... Nothing really special here.
    class SwingFrame extends JFrame {
        private static final long serialVersionUID = 1L;

        JPanel contentPane;
        JPanel mainPanel = new JPanel();
        Canvas comp = null;
        JButton coolButton = new JButton();
        JButton uncoolButton = new JButton();
        JPanel spPanel = new JPanel();
        JScrollPane scrollPane = new JScrollPane();
        JTree jTree1 = new JTree();
        JCheckBox scaleBox = new JCheckBox("Scale GL Image");
        JPanel colorPanel = new JPanel();
        JLabel colorLabel = new JLabel("BG Color:");
        JMECanvasImplementor impl;

        // Construct the frame
        public SwingFrame() {
            addWindowListener(new WindowAdapter() {
                public void windowClosing(WindowEvent e) {
                    dispose();
                }
            });

            init();
            pack();


            // MAKE SURE YOU REPAINT SOMEHOW OR YOU WON'T SEE THE UPDATES...
            new Thread() {
                { setDaemon(true); }
                public void run() {
                    while (true) {
                        comp.repaint();
                        yield();
                    }
                }
            }.start();

           
        }

        // Component initialization
        private void init() {
            contentPane = (JPanel) this.getContentPane();
            contentPane.setLayout(new BorderLayout());

            mainPanel.setLayout(new GridBagLayout());

            setTitle("JME - SWING INTEGRATION TEST");

            //


GL STUFF

            // make the canvas:
            comp = DisplaySystem.getDisplaySystem("lwjgl").createCanvas(width, height);

            // add a listener... if window is resized, we can do something about it.
            comp.addComponentListener(new ComponentAdapter() {
                public void componentResized(ComponentEvent ce) {
                    doResize();
                }
            });

            // Important!  Here is where we add the guts to the panel:
            impl = new MyImplementor(width, height);
            ((JMECanvas) comp).setImplementor(impl);
           
            input = new InputHandler();
            ((JMECanvas) comp).setUpdateInput(true);
            try {
             MouseInput.setProvider("AWT");      
             KeyInput.setProvider("AWT");
          } catch(Exception e) {
             
          }   
            ((AWTKeyInput) KeyInput.get()).setEnabled(true);
          KeyListener kl = (KeyListener) KeyInput.get();

          comp.addKeyListener(kl);

          ((AWTMouseInput) MouseInput.get()).setEnabled(true);
          ((AWTMouseInput) MouseInput.get()).setDragOnly(false);
          ((AWTMouseInput) MouseInput.get()).setRelativeDelta(comp);
          comp.addMouseListener((MouseListener) MouseInput.get());
          comp.addMouseWheelListener((MouseWheelListener) MouseInput.get());
          comp.addMouseMotionListener((MouseMotionListener) MouseInput.get());
           
           
           
           
            //
END OF GL STUFF

            coolButton.setText("Cool Button");
            uncoolButton.setText("Uncool Button");

            colorPanel.setBackground(java.awt.Color.black);
            colorPanel.setToolTipText("Click here to change Panel BG color.");
            colorPanel.setBorder(BorderFactory.createRaisedBevelBorder());
            colorPanel.addMouseListener(new java.awt.event.MouseAdapter() {
                public void mouseClicked(MouseEvent e) {
                    java.awt.Color color = JColorChooser.showDialog(
                            SwingFrame.this, "Choose new background color:",
                            colorPanel.getBackground());
                    if (color == null)
                        return;
                    colorPanel.setBackground(color);
                    comp.setBackground(color);
                }
            });

            scaleBox.setOpaque(false);
            scaleBox.setSelected(true);
            scaleBox.addActionListener(new ActionListener() {
                public void actionPerformed(ActionEvent e) {
                    if (comp != null)
                        doResize();
                }
            });

            spPanel.setLayout(new BorderLayout());
            contentPane.add(mainPanel, BorderLayout.WEST);
            mainPanel.add(scaleBox,
                    new GridBagConstraints(0, 0, 1, 1, 0.0, 0.0,
                            GridBagConstraints.CENTER,
                            GridBagConstraints.HORIZONTAL, new Insets(5, 5, 0,
                                    5), 0, 0));
            mainPanel.add(colorLabel,
                    new GridBagConstraints(0, 1, 1, 1, 0.0, 0.0,
                            GridBagConstraints.CENTER,
                            GridBagConstraints.HORIZONTAL, new Insets(5, 5, 0,
                                    5), 0, 0));
            mainPanel.add(colorPanel, new GridBagConstraints(0, 2, 1, 1, 0.0,
                    0.0, GridBagConstraints.CENTER, GridBagConstraints.NONE,
                    new Insets(5, 5, 0, 5), 25, 25));
            mainPanel.add(coolButton,
                    new GridBagConstraints(0, 3, 1, 1, 0.0, 0.0,
                            GridBagConstraints.CENTER,
                            GridBagConstraints.HORIZONTAL, new Insets(5, 5, 0,
                                    5), 0, 0));
            mainPanel.add(uncoolButton,
                    new GridBagConstraints(0, 4, 1, 1, 0.0, 0.0,
                            GridBagConstraints.CENTER,
                            GridBagConstraints.HORIZONTAL, new Insets(5, 5, 0,
                                    5), 0, 0));
            mainPanel.add(spPanel, new GridBagConstraints(0, 5, 1, 1, 1.0, 1.0,
                    GridBagConstraints.CENTER, GridBagConstraints.BOTH,
                    new Insets(5, 5, 0, 5), 0, 0));
            spPanel.add(scrollPane, BorderLayout.CENTER);
           
            scrollPane.setViewportView(jTree1);
            comp.setBounds(0, 0, width, height);
            contentPane.add(comp, BorderLayout.CENTER);
           
           
           
        }

        protected void doResize() {
            if (scaleBox != null && scaleBox.isSelected()) {
                impl.resizeCanvas(comp.getWidth(), comp.getHeight());
            } else {
                impl.resizeCanvas(width, height);
            }
        }

        // Overridden so we can exit when window is closed
        protected void processWindowEvent(WindowEvent e) {
            super.processWindowEvent(e);
            if (e.getID() == WindowEvent.WINDOW_CLOSING) {
                System.exit(0);
            }
        }
    }

   
    // IMPLEMENTING THE SCENE:
   
    class MyImplementor extends SimpleCanvasImpl {

        private Quaternion rotQuat;
        private float angle = 0;
        private Vector3f axis;
        private Box box;
      long startTime = 0;
      long fps = 0;         
      
      Desktop desktop;
      Timer timer;
        public MyImplementor(int width, int height) {
            super(width, height);
        }

        public void simpleSetup() {

            // Normal Scene setup stuff...
            rotQuat = new Quaternion();
            axis = new Vector3f(1, 1, 0.5f);
            axis.normalizeLocal();

            Vector3f max = new Vector3f(5, 5, 5);
            Vector3f min = new Vector3f(-5, -5, -5);

            box = new Box("Box", min, max);
            box.setModelBound(new BoundingBox());
            box.updateModelBound();
            box.setLocalTranslation(new Vector3f(0, 0, -10));
            box.setRenderQueueMode(Renderer.QUEUE_SKIP);
            rootNode.attachChild(box);

            box.setRandomColors();

            TextureState ts = renderer.createTextureState();
            ts.setEnabled(true);
            ts.setTexture(TextureManager.loadTexture(JMESwingDesktopTest.class
                    .getClassLoader().getResource(
                            "jmetest/data/images/Monkey.jpg"),
                    Texture.MM_LINEAR, Texture.FM_LINEAR));

            rootNode.setRenderState(ts);
          
            KeyboardLookHandler lookHandler = new KeyboardLookHandler( cam, 50, 1 );
            input.addToAttachedHandlers( lookHandler );
            desktop = new Desktop(Color.blue, rootNode, timer, input);
            startTime = System.currentTimeMillis() + 5000;
            timer = Timer.getTimer(DisplaySystem.DISPLAY_SYSTEM_LWJGL);
        };

        public void simpleUpdate() {
            // Code for rotating the box... no surprises here.
            if (tpf < 1) {
                angle = angle + (tpf * 25);
                if (angle > 360) {
                    angle = 0;
                }
            }
            input.update(timer.getTime());
            rotQuat.fromAngleNormalAxis(angle * FastMath.DEG_TO_RAD, axis);
            box.setLocalRotation(rotQuat);
           
         if (startTime > System.currentTimeMillis()) {
            fps++;
         } else {
            long timeUsed = 5000 + (startTime - System.currentTimeMillis());
            startTime = System.currentTimeMillis() + 5000;
            System.out.println(fps + " frames in " + (float) (timeUsed / 1000f) + " seconds = "
                  + (fps / (timeUsed / 1000f))+" FPS (average)");
            fps = 0;
         }            
        }
    }
}




package jmetest.util;

import java.awt.Color;
import java.awt.FlowLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;

import javax.swing.JButton;
import javax.swing.JDesktopPane;
import javax.swing.JInternalFrame;

import jmetest.awt.swingui.TestJMEDesktop;

import com.jme.bounding.OrientedBoundingBox;
import com.jme.image.Texture;
import com.jme.input.AbsoluteMouse;
import com.jme.input.InputHandler;
import com.jme.math.Quaternion;
import com.jme.math.Vector3f;
import com.jme.renderer.Renderer;
import com.jme.scene.Controller;
import com.jme.scene.Node;
import com.jme.scene.shape.Box;
import com.jme.scene.state.LightState;
import com.jme.scene.state.TextureState;
import com.jme.system.DisplaySystem;
import com.jme.util.TextureManager;
import com.jme.util.Timer;
import com.jmex.awt.swingui.JMEDesktop;

public class Desktop{
   
   
    public JMEDesktop jmeDesktop;
   
    private Node desktopNode;
    private DisplaySystem display;
    Timer timer;
    Node rootNode;
   
   
    public Desktop(Color color, Node rootNode, Timer timer, InputHandler input) {
      // super("dtn");
       this.rootNode = rootNode;
       this.timer = timer;
      
       jmeDesktop = new JMEDesktop( "dk" );
       display = DisplaySystem.getDisplaySystem();
       jmeDesktop.setup( display.getWidth(), display.getHeight(), false, input );
        jmeDesktop.setLightCombineMode( LightState.OFF );
        desktopNode = new Node("desktop node" );
        desktopNode.attachChild(jmeDesktop);
      
      
       rootNode.attachChild(desktopNode);
       jmeDesktop.getJDesktop().setBackground( color );
       createBoxBorder();
       perspective();
       createSwingStuff();
      
      
      
    }
   
    private void createBoxBorder() {
           //create a border from boxes around the desktop
           float borderWidth = 10;
           float halfBorderWidth = borderWidth / 2;
           int halfDesktopWidth = jmeDesktop.getJDesktop().getWidth() / 2;
           int halfDesktopHeight = jmeDesktop.getJDesktop().getHeight() / 2;

           Box top = new Box( "top border", new Vector3f(),
                   halfDesktopWidth + halfBorderWidth,
                   halfBorderWidth, halfBorderWidth );
           top.getLocalTranslation().set( 0, - halfDesktopHeight, 0 );
           top.setModelBound( new OrientedBoundingBox() );
           top.updateModelBound();
           desktopNode.attachChild( top );

           Box bottom = new Box( "bottom border", new Vector3f(),
                   halfDesktopWidth + halfBorderWidth,
                   halfBorderWidth, halfBorderWidth );
           bottom.getLocalTranslation().set( 0, halfDesktopHeight, 0 );
           bottom.setModelBound( new OrientedBoundingBox() );
           bottom.updateModelBound();
           desktopNode.attachChild( bottom );

           Box left = new Box( "left border", new Vector3f(),
                   halfBorderWidth,
                   halfDesktopHeight + halfBorderWidth,
                   halfBorderWidth );
           left.getLocalTranslation().set( - halfDesktopWidth, 0, 0 );
           left.setModelBound( new OrientedBoundingBox() );
           left.updateModelBound();
           desktopNode.attachChild( left );

           Box right = new Box( "right border", new Vector3f(),
                   halfBorderWidth,
                   halfDesktopHeight + halfBorderWidth,
                   halfBorderWidth );
           right.getLocalTranslation().set( halfDesktopWidth, 0, 0 );
           right.setModelBound( new OrientedBoundingBox() );
           right.updateModelBound();
           desktopNode.attachChild( right );
       }

       private void perspective() {
           desktopNode.getLocalRotation().fromAngleNormalAxis( -0.7f, new Vector3f( 1, 0, 0 ) );
           desktopNode.setLocalScale( 24f / jmeDesktop.getJDesktop().getWidth() );
           desktopNode.getLocalTranslation().set( 0, 0, 0 );
           desktopNode.setRenderQueueMode( Renderer.QUEUE_TRANSPARENT );
       }

       private void fullScreen() {
           final DisplaySystem display = DisplaySystem.getDisplaySystem();

           desktopNode.getLocalRotation().set( 0, 0, 0, 1 );
           desktopNode.getLocalTranslation().set( display.getWidth() / 2, display.getHeight() / 2, 0 );
           desktopNode.getLocalScale().set( 1, 1, 1 );
           desktopNode.setRenderQueueMode( Renderer.QUEUE_ORTHO );
       }


       private AbsoluteMouse cursor;

       protected void createSwingStuff() {
           final JDesktopPane desktopPane = jmeDesktop.getJDesktop();
           desktopPane.removeAll();

           createSwingInternalFrame( desktopPane, "My Frame 1", 10, 150 );
           createSwingInternalFrame( desktopPane, "My Frame 2", 20, 300 );
           createSwingInternalFrame( desktopPane, null, 400, 350 );
           JButton fullScreenButton = new JButton( "<html><big>toggle fullscreen</big></html>" );
           fullScreenButton.setSize( fullScreenButton.getPreferredSize() );
           fullScreenButton.setLocation( ( display.getWidth() - fullScreenButton.getWidth() ) / 2,
                   display.getHeight() - 40 - fullScreenButton.getHeight() / 2 );
           desktopPane.add( fullScreenButton );
           fullScreenButton.addActionListener( new ActionListener() {
               public void actionPerformed( ActionEvent e ) {
                   if ( desktopNode.getRenderQueueMode() == Renderer.QUEUE_ORTHO ) {
                       perspective();
                   }
                   else {
                       fullScreen();
                   }
               }
           } );

           createRotateButton( desktopPane, 0.25f );
           createRotateButton( desktopPane, -0.25f );
           createRotateButton( desktopPane, 0.15f );
           createRotateButton( desktopPane, -0.15f );
           createRotateButton( desktopPane, 0.45f );
           createRotateButton( desktopPane, -0.45f );

      
           desktopPane.repaint();
           desktopPane.revalidate();
       }

       private void createRotateButton( JDesktopPane parent, final float direction ) {
           JButton button = new JButton( direction < 0 ? "<" : ">" );
           button.setSize( button.getPreferredSize() );
           button.setLocation( (int) ( ( display.getWidth() - button.getWidth() ) / 2
                   + direction * display.getWidth() ), display.getHeight() - 40 - button.getHeight() / 2 );
           parent.add( button );
           button.addActionListener( new ActionListener() {
               public void actionPerformed( ActionEvent e ) {
                   if ( desktopNode.getRenderQueueMode() != Renderer.QUEUE_ORTHO ) {
                       desktopNode.addController( new Controller() {
                           private static final long serialVersionUID = 1L;

                           float length = 1;
                           float endTime = timer.getTimeInSeconds() + length;
                           Quaternion start = new Quaternion().set( desktopNode.getLocalRotation() );
                           Quaternion finish = new Quaternion().set( desktopNode.getLocalRotation() ).multLocal(
                                   new Quaternion().fromAngleNormalAxis( direction, new Vector3f( 0, 1, 0 ) ) );

                           public void update( float time ) {
                               if ( timer.getTimeInSeconds() > endTime ) {
                                   desktopNode.removeController( this );
                               }
                               else {
                                   desktopNode.getLocalRotation().slerp( finish, start, ( endTime - timer.getTimeInSeconds() ) / length );
                                   desktopNode.getLocalRotation().normalize();
                               }
                           }
                       } );
                   }
               }
           } );
       }


       private void createSwingInternalFrame( final JDesktopPane desktopPane, final String title, int x, int y ) {
           final JInternalFrame internalFrame = new JInternalFrame( title );
           if ( title == null ) {
               internalFrame.putClientProperty( "JInternalFrame.isPalette", Boolean.TRUE );
           }
           internalFrame.setLocation( x, y );
           internalFrame.setResizable( true );

           internalFrame.getContentPane().setLayout( new FlowLayout() );
       
       }
       private void create3DStuff() {
           // Normal Scene setup stuff...
           final Vector3f axis = new Vector3f( 1, 1, 0.5f ).normalizeLocal();

           final Box box = new Box( "Box", new Vector3f( -5, -5, -5 ), new Vector3f( 5, 5, 5 ) );
           box.setModelBound( new OrientedBoundingBox() );
           box.updateModelBound();
           box.setLocalTranslation( new Vector3f( 0, 0, -10 ) );
           box.setRandomColors();
           box.setLightCombineMode( LightState.OFF );

           TextureState ts = display.getRenderer().createTextureState();
           ts.setEnabled( true );
           ts.setTexture( TextureManager.loadTexture( TestJMEDesktop.class
                   .getClassLoader().getResource(
                   "jmetest/data/images/Monkey.jpg" ),
                   Texture.MM_LINEAR, Texture.FM_LINEAR ) );
           box.setRenderState( ts );

           //let the box rotate
           box.addController( new Controller() {
               private static final long serialVersionUID = 1L;

               public void update( float time ) {
                   box.getLocalRotation().fromAngleNormalAxis( timer.getTimeInSeconds(), axis );
               }
           } );

           rootNode.attachChild( box );
       }

       protected void cleanup() {
           jmeDesktop.dispose();
         
       }
}




Any more assistance - please let me know

BTW, am doing picking in the SwingFrame, therefore the provider is AWT


MouseInput.setProvider("AWT");      
KeyInput.setProvider("AWT");

Hi Irrisor…



JMEDesktop is great - dont worry about the above, im gonna lose the swing frame and convert over all the jpanels, putting them within JMEDesktop.



On looking under the hood, there are many issues with swing created in its own thread outside of jme.

cool! seems my todo list just got a bit shorter :)    (though I would have liked Swing-outside working with JMEDesktop)

Strikes me that you need to create the swing Jframe first, then add the canvas. As the frame is created, the swing thread owner wont be JME

kidneybean said:

Strikes me that you need to create the swing Jframe first, then add the canvas. As the frame is created, the swing thread owner wont be JME

:? no idea what you are talking about

Lol,



Blah blah threads, blah blah Monitors , blah blah dont cross the beams



Nothing new, just seen the prior discussion using Events