Search code examples
javaswingappletjavafx-2japplet

How do I use javax.swing components in an application?


Disclaimer: I am very new to Java, but I've been building .NET applications for 13 years.

I'm trying to build this Java application that does some basic calculations for tutoring. It's honestly not that big of a program, but I can't even get it to the Hello, World! state! I have a requirement that's making it difficult:

GUI should be built using javax.swing components jButton, jLabel, jTextField, jTextArea, jFrame, and jPanel.

So, I downloaded NetBeans 7.3 and created a JavaFX in Swing application. The default code obviously works but it uses Button instead of JButton:

private void createScene() {
    Button btn = new Button();
    btn.setText("Say 'Hello World'");
    btn.setOnAction(new EventHandler<ActionEvent>() {
        @Override
        public void handle(ActionEvent event) {
            System.out.println("Hello World!");
        }
    });
    StackPane root = new StackPane();
    root.getChildren().add(btn);
    fxContainer.setScene(new Scene(root));
}

so I when I change it to use a JButton I have to also change the type the root is built from. While banging my head against the wall I found an example here (not directly related) that used the JRootPane and I thought that might work in place of the StackPane. So I refactored the code like this:

private void createScene() {
    JButton btn = new JButton();
    btn.setText("Say 'Hello World'");
    JRootPane root = new JRootPane();
    root.getContentPane().add(btn);
    fxContainer.setScene(new Scene(root));
}

and that code is fine except for fxContainer.setScene(new Scene(root)); because root isn't a Parent.

FYI, the application class implements JApplet and has a main and init that looks like this:

public static void main(String[] args) {
    SwingUtilities.invokeLater(new Runnable() {
        @Override
        public void run() {
            try {
                UIManager.setLookAndFeel("com.sun.java.swing.plaf.nimbus.NimbusLookAndFeel");
            } catch (Exception e) {
            }
            
            JFrame frame = new JFrame("Tutoring Calculator");
            frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
            
            JApplet applet = new TutoringCalculator();
            applet.init();
            
            frame.setContentPane(applet.getContentPane());
            
            frame.pack();
            frame.setLocationRelativeTo(null);
            frame.setVisible(true);
            
            applet.start();
        }
    });
}

@Override
public void init() {
    fxContainer = new JFXPanel();
    fxContainer.setPreferredSize(new Dimension(JFXPANEL_WIDTH_INT, JFXPANEL_HEIGHT_INT));
    add(fxContainer, BorderLayout.CENTER);
    // create JavaFX scene
    Platform.runLater(new Runnable() {
        @Override
        public void run() {
            createScene();
        }
    });
}

How can I fulfill the requirement stated above? Am I really going about this whole thing the wrong way?

SSCCE

/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package tutoringcalculator;

import java.awt.BorderLayout;
import java.awt.Dimension;
import javafx.application.Platform;
import javafx.embed.swing.JFXPanel;
import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.layout.StackPane;
import javax.swing.JApplet;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JRootPane;
import javax.swing.SwingUtilities;
import javax.swing.UIManager;

/**
 *
 * @author Owner
 */
public class TutoringCalculator extends JApplet {
    
    private static final int JFXPANEL_WIDTH_INT = 300;
    private static final int JFXPANEL_HEIGHT_INT = 250;
    private static JFXPanel fxContainer;

    /**
     * @param args the command line arguments
     */
    public static void main(String[] args) {
        SwingUtilities.invokeLater(new Runnable() {
            @Override
            public void run() {
                try {
                    UIManager.setLookAndFeel("com.sun.java.swing.plaf.nimbus.NimbusLookAndFeel");
                } catch (Exception e) {
                }
                
                JFrame frame = new JFrame("Tutoring Calculator");
                frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
                
                JApplet applet = new TutoringCalculator();
                applet.init();
                
                frame.setContentPane(applet.getContentPane());
                
                frame.pack();
                frame.setLocationRelativeTo(null);
                frame.setVisible(true);
                
                applet.start();
            }
        });
    }
    
    @Override
    public void init() {
        fxContainer = new JFXPanel();
        fxContainer.setPreferredSize(new Dimension(JFXPANEL_WIDTH_INT, JFXPANEL_HEIGHT_INT));
        add(fxContainer, BorderLayout.CENTER);
        // create JavaFX scene
        Platform.runLater(new Runnable() {
            @Override
            public void run() {
                createScene();
            }
        });
    }
    
    private void createScene() {
        JButton btn = new JButton();
        btn.setText("Say 'Hello World'");
        JRootPane root = new JRootPane();
        root.getContentPane().add(btn);
        fxContainer.setScene(new Scene(root));
    }
}

Solution

  • This code works either as an applet or desktop app. here:

    import java.awt.BorderLayout;
    import java.awt.Dimension;
    import javax.swing.*;
    
    // <applet code=TutoringCalculator width=400 height=400></applet>
    public class TutoringCalculator extends JApplet {
    
        // The size of an applet is set by the HTML!
        //private static final int JFXPANEL_WIDTH_INT = 300;
        //private static final int JFXPANEL_HEIGHT_INT = 250;
    
        public static void main(String[] args) {
            SwingUtilities.invokeLater(new Runnable() {
                @Override
                public void run() {
                    JFrame frame = new JFrame("Tutoring Calculator");
                    frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    
                    JApplet applet = new TutoringCalculator();
                    applet.init();
    
                    frame.setContentPane(applet.getContentPane());
    
                    frame.pack();
                    frame.setLocationRelativeTo(null);
                    frame.setVisible(true);
    
                    applet.start();
                }
            });
        }
    
        private JPanel swingContainer;
    
        @Override
        public void init() {
            swingContainer = new JPanel(new BorderLayout());
            add(swingContainer, BorderLayout.CENTER);
            createScene();
        }
    
        private void createScene() {
            JButton btn = new JButton();
            btn.setText("Say 'Hello World'");
            JRootPane root = new JRootPane();
            root.getContentPane().add(btn);
            swingContainer.add(root);
        }
    }
    

    I could not be bothered figuring why you are using a RootPane so I left that as is.

    Further tips

    • The spec. mentions JFrame but not JApplet. Since applets are significantly harder to develop, debug and deploy, I suggest you focus entirely on getting it working in a frame.
    • For frame positioning, you cannot go by setLocationByPlatform(true). See this answer for demo.