'Converting from Swing to JavaFX? (Migration Guide)

When converting a Swing project to a JavaFx project, which classes from JavaFx match up to the Swing classes?

A 1-1 matchup is best.

I am not looking for integration with Swing, but a complete makeover.



Solution 1:[1]

The following are some of the basic classes:

  • Swing -> JavaFx
  • JFrame -> Application & Stage (if you extend JFrame in your main class, Application.launch() can be used to launch one that extends Application). Stage is explicitly JavaFx and necessary for creating a Window. You will need to use an instance of it, rather than an instance of JFrame.
  • JPanel -> Scene & Pane (Scene matches up with JPanel, but your classes should extend Pane. Then build a scene from the pane. Pane's are layouts in JavaFX)
  • JButton -> Button
  • JLabel -> Label
  • In many cases, removing the J will do the trick...
  • JOptionPane -> Dialog (but, not always)
  • ActionListener -> EventHandler< ActionEvent >) (Need to create a new method/class in JavaFx for each action that you need, unlike Swing's one method does all)

UPDATE Using event handlers should be easier now with Java 8+, with the added capability of functional interfaces, which JavaFX now supports.

Example Swing (the basic interface for a game I made)

public class Interface extends JFrame {

public static void main(String[] args) {
    new Interface();
}

private CardLayout layout;
private JPanel manager;
private Introduction start;
private MainDisplay display;

public Interface() {
    super("Demo");
    this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    this.setMinimumSize(new Dimension(750, 500));
    this.setPreferredSize(new Dimension(750, 500));
    this.setMaximumSize(new Dimension(750, 500));

    setUp();

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

private void setUp() {
    layout = new CardLayout();
    manager = new JPanel(layout);
    this.add(manager);

    start = new Introduction();
    manager.add(start, INTRODUCTION);

    display = new MainDisplay();
    manager.add(display);

    layout.show(manager);
}

public class Introduction extends JPanel implements ActionListener {

    private static final int LOAD = 0;
    private static final int SAVE = 1;
    private JButton start;
    private JButton toGame;
    private JButton load;
    private JButton save;
    private JButton exit;

    public Introduction() {
        setUp();
    }

    private void setUp() {
        SpringLayout manager = new SpringLayout();
        this.setLayout(manager);

        JLabel title = new JLabel("Demo");
        title.setFont(new Font(Font.SERIF, Font.BOLD, 60));
        manager.putConstraint(SpringLayout.HORIZONTAL_CENTER, title, 0,
                SpringLayout.HORIZONTAL_CENTER, this);
        manager.putConstraint(SpringLayout.NORTH, title, 10, SpringLayout.NORTH,
                this);
        this.add(title);

        start = new JButton("New Game");
        start.setFont(new Font(Font.SERIF, Font.PLAIN, 16));
        start.addActionListener(this);
        manager.putConstraint(SpringLayout.HORIZONTAL_CENTER, start, -250,
                SpringLayout.HORIZONTAL_CENTER, this);
        manager.putConstraint(SpringLayout.NORTH, start, 50, SpringLayout.SOUTH,
                title);
        this.add(start);

        toGame = new JButton("Continue");
        toGame.setFont(new Font(Font.SERIF, Font.PLAIN, 16));
        toGame.addActionListener(this);
        toGame.setEnabled(false);
        manager.putConstraint(SpringLayout.HORIZONTAL_CENTER, toGame, -250,
                SpringLayout.HORIZONTAL_CENTER, this);
        manager.putConstraint(SpringLayout.NORTH, toGame, 10, SpringLayout.SOUTH,
                start);
        this.add(toGame);

        load = new JButton("Load Game");
        load.setFont(new Font(Font.SERIF, Font.PLAIN, 16));
        load.addActionListener(this);
        manager.putConstraint(SpringLayout.HORIZONTAL_CENTER, load, -250,
                SpringLayout.HORIZONTAL_CENTER, this);
        manager.putConstraint(SpringLayout.NORTH, load, 10, SpringLayout.SOUTH,
                toGame);
        this.add(load);

        save = new JButton("Save Game");
        save.setFont(new Font(Font.SERIF, Font.PLAIN, 16));
        save.addActionListener(this);
        save.setEnabled(false);
        manager.putConstraint(SpringLayout.HORIZONTAL_CENTER, save, -250,
                SpringLayout.HORIZONTAL_CENTER, this);
        manager.putConstraint(SpringLayout.NORTH, save, 10, SpringLayout.SOUTH, load);
        this.add(save);

        exit = new JButton("Exit Game");
        exit.setFont(new Font(Font.SERIF, Font.PLAIN, 16));
        exit.setToolTipText("Saves the current game, and exits the program.");
        exit.addActionListener(this);
        manager.putConstraint(SpringLayout.HORIZONTAL_CENTER, exit, -250,
                SpringLayout.HORIZONTAL_CENTER, this);
        manager.putConstraint(SpringLayout.NORTH, exit, 10, SpringLayout.SOUTH, save);
        this.add(exit);
    }

    private void perform(int option) {
        JFileChooser chooser = new JFileChooser();
        chooser.setFileFilter(new TextFileFilter());
        if (option == LOAD) {
            int choice = chooser.showDialog(this, "Load Game");
            if (choice == JFileChooser.APPROVE_OPTION)
                chooser.getSelectedFile();
        } else if (option == SAVE) {
            int choice = chooser.showDialog(this, "Save Game");
            if (choice == JFileChooser.APPROVE_OPTION)
                chooser.getSelectedFile();
        }
    }

    @Override
    public void actionPerformed(ActionEvent e) {
        if (display.isRunning()) {
            if (e.getSource() == start || e.getSource() == load) {
                String verify = "A game is currently running.  Are you sure you want to start a new game?"
                        + "\r\nAny previous game data will be deleted.";
                int choice = JOptionPane.showConfirmDialog(this, verify,
                        "New Game - Warning", JOptionPane.YES_NO_OPTION,
                        JOptionPane.WARNING_MESSAGE);

                if (choice == JOptionPane.NO_OPTION)
                    return;
            }
        }

        if (e.getSource() == start) {
            display.start();
            layout.show(manager, MAIN_DISPLAY);
            toGame.setEnabled(true);
            save.setEnabled(true);
        } else if (e.getSource() == toGame)
            layout.show(manager, MAIN_DISPLAY);
        else if (e.getSource() == load)
            perform(LOAD);
        else if (e.getSource() == save)
            perform(SAVE);
        else if (e.getSource() == exit) {
            perform(SAVE);
            Interface.this.setVisible(false);
            Interface.this.dispose();
        }
    }

}

public class MainDisplay extends JPanel implements ActionListener {

    private static final long serialVersionUID = 1L;
    private boolean running;
    private JButton overview;
    private JButton map;
    private JButton ranking;
    private JButton reports;
    private JButton home;

    public MainDisplay() {
        running = false;
        setUp();
    }

    public boolean isRunning() {
        return running;
    }

    private void setUp() {
        SpringLayout manager = new SpringLayout();
        this.setLayout(manager);

        ranking = new JButton("Ranking");
        ranking.setFont(new Font(Font.SERIF, Font.PLAIN, 10));
        ranking.addActionListener(this);
        manager.putConstraint(SpringLayout.HORIZONTAL_CENTER, ranking, 0,
                SpringLayout.HORIZONTAL_CENTER, this);
        manager.putConstraint(SpringLayout.NORTH, ranking, 10, SpringLayout.NORTH,
                this);
        this.add(ranking);

        map = new JButton("Map");
        map.setFont(new Font(Font.SERIF, Font.PLAIN, 10));
        map.addActionListener(this);
        manager.putConstraint(SpringLayout.EAST, map, -10, SpringLayout.WEST,
                ranking);
        manager.putConstraint(SpringLayout.NORTH, map, 10, SpringLayout.NORTH, this);
        this.add(map);

        overview = new JButton("Overview");
        overview.setFont(new Font(Font.SERIF, Font.PLAIN, 10));
        overview.addActionListener(this);
        manager.putConstraint(SpringLayout.EAST, overview, -10, SpringLayout.WEST,
                map);
        manager.putConstraint(SpringLayout.NORTH, overview, 10, SpringLayout.NORTH,
                this);
        this.add(overview);

        reports = new JButton("Reports");
        reports.setFont(new Font(Font.SERIF, Font.PLAIN, 10));
        reports.addActionListener(this);
        manager.putConstraint(SpringLayout.WEST, reports, 10, SpringLayout.EAST,
                ranking);
        manager.putConstraint(SpringLayout.NORTH, reports, 10, SpringLayout.NORTH,
                this);
        this.add(reports);

        home = new JButton("Home");
        home.setFont(new Font(Font.SERIF, Font.PLAIN, 10));
        home.addActionListener(this);
        manager.putConstraint(SpringLayout.WEST, home, 10, SpringLayout.EAST,
                reports);
        manager.putConstraint(SpringLayout.NORTH, home, 10, SpringLayout.NORTH, this);
        this.add(home);
    }

    public void start() {
        running = true;
    }

    public void actionPerformed(ActionEvent e) {
        if (e.getSource() == home) {
            layout.show(manager, INTRODUCTION);
        }
    }

}

public static final class TextFileFilter extends FileFilter {

    private static final String FILE_EXTENSION = "tra";

    @Override
    public boolean accept(File f) {
        if (f.isDirectory())
            return true;
        if (f.getName().toLowerCase().endsWith(FILE_EXTENSION))
            return true;
        return false;
    }

    @Override
    public String getDescription() {
        return "Demo";
    }
}

}

JavaFx Example (Almost the same example in JavaFx)

public class Interface extends Application {

public static void main(String[] args) {
    Application.launch(Interface.class, args);
}

private static final int WIDTH = 750;
private static final int HEIGHT = 500;
private static Stage stage;
private static Introduction start;
private static MainDisplay display;
private static Scene startScene;
private static Scene displayScene;

public Interface() {
    start = new Introduction();
    display = new MainDisplay();
    startScene = new Scene(start, WIDTH, HEIGHT);
    displayScene = new Scene(display, WIDTH, HEIGHT);
}

@Override
public void start(Stage primaryStage) throws Exception {
    Interface.stage = primaryStage;

    stage.setTitle(Constants.TITLE);
    stage.setResizable(false);
    stage.setWidth(WIDTH);
    stage.setHeight(HEIGHT);

    stage.setScene(startScene);
    stage.show();
}

public class Introduction extends BorderPane {

    private static final int LOAD = 0;
    private static final int SAVE = 1;
    private Button toGame;
    private Button save;
    public Introduction() {
        setUp();
    }

    private void setUp() {

        this.setBackground(
                new Background(new BackgroundFill(Color.BLACK, null, null)));

        VBox menu = new VBox();
        menu.setSpacing(10);

        Label title = new Label(Constants.TITLE.toUpperCase());
        title.setFont(Font.font("Arial", FontWeight.THIN, 60));
        title.setTextFill(Color.RED);
        menu.getChildren().add(title);

        int btnWidth = 300;
        Background menuBkg = new Background(new BackgroundFill(null, null, null));
        Border menuBorder = new Border(new BorderStroke(Color.RED,
                BorderStrokeStyle.SOLID, new CornerRadii(10), null));

        Button start = new Button(Constants.START.toUpperCase());
        start.setFont(Font.font("Times New Roman", 16));
        start.setTextFill(Color.WHITE);
        start.setPrefWidth(btnWidth);
        start.setBackground(menuBkg);
        start.setBorder(menuBorder);
        start.setOnAction(new StartHandler());

        toGame = new Button(Constants.CONTINUE.toUpperCase());
        toGame.setFont(Font.font("Times New Roman", 16));
        toGame.setTextFill(Color.WHITE);
        toGame.setPrefWidth(btnWidth);
        toGame.setBackground(menuBkg);
        toGame.setBorder(menuBorder);
        toGame.setDisable(true);
        toGame.setOnAction(new ContinueHandler());

        Button load = new Button(Constants.LOAD.toUpperCase());
        load.setFont(Font.font("Times New Roman", 16));
        load.setTextFill(Color.WHITE);
        load.setPrefWidth(btnWidth);
        load.setBackground(menuBkg);
        load.setBorder(menuBorder);
        load.setOnAction(new LoadHandler());

        save = new Button(Constants.SAVE.toUpperCase());
        save.setFont(Font.font("Times New Roman", 16));
        save.setTextFill(Color.WHITE);
        save.setPrefWidth(btnWidth);
        save.setBackground(menuBkg);
        save.setBorder(menuBorder);
        save.setDisable(true);
        save.setOnAction(new SaveHandler());

        Button ranking = new Button(Constants.RANKING.toUpperCase());
        ranking.setFont(Font.font("Times New Roman", 16));
        ranking.setTextFill(Color.WHITE);
        ranking.setPrefWidth(btnWidth);
        ranking.setBackground(menuBkg);
        ranking.setBorder(menuBorder);
        ranking.setOnAction(new RankingHandler());

        Button exit = new Button(Constants.EXIT.toUpperCase());
        exit.setFont(Font.font("Times New Roman", 16));
        exit.setTextFill(Color.WHITE);
        exit.setPrefWidth(btnWidth);
        exit.setBackground(menuBkg);
        exit.setBorder(menuBorder);
        exit.setTooltip(new Tooltip(Constants.EXIT_TOOLTIP));
        exit.setOnAction(new ExitHandler());

        menu.getChildren().addAll(start, toGame, load, save, ranking, exit);
        menu.setAlignment(Pos.CENTER);
        this.setCenter(menu);
    }

    private void performIO(int option) {
        FileChooser chooser = new FileChooser();
        ExtensionFilter ext = new ExtensionFilter(Constants.EXT_DESCRIPTION, ".pt");
        chooser.setSelectedExtensionFilter(ext);
        if (option == LOAD) {
            chooser.setTitle(Constants.LOAD);
            File choice = chooser.showOpenDialog(stage);
        } else if (option == SAVE) {
            chooser.setTitle(Constants.SAVE);
            File choice = chooser.showSaveDialog(stage);
        }
    }

    private boolean verifyRestart() {
        Alert alert = new Alert(AlertType.WARNING, Constants.START_WARNING_MESSAGE,
                ButtonType.YES, ButtonType.NO);
        alert.setTitle(Constants.START_WARNING);
        alert.showAndWait();

        if (alert.getResult() == ButtonType.YES)
            return true;
        return false;
    }

    private class StartHandler implements EventHandler<ActionEvent> {

        @Override
        public void handle(ActionEvent event) {
            if (display.isRunning()) {
                if (!verifyRestart())
                    return;
            }

            display.start();
            stage.setScene(displayScene);
            toGame.setDisable(false);
            save.setDisable(false);
        }

    }

    private class ContinueHandler implements EventHandler<ActionEvent> {

        @Override
        public void handle(ActionEvent event) {
            stage.setScene(displayScene);
        }

    }

    private class LoadHandler implements EventHandler<ActionEvent> {

        @Override
        public void handle(ActionEvent event) {
            if (display.isRunning()) {
                if (!verifyRestart())
                    return;
            }

            performIO(LOAD);
        }

    }

    private class SaveHandler implements EventHandler<ActionEvent> {

        @Override
        public void handle(ActionEvent event) {
            performIO(SAVE);
        }

    }

    private class RankingHandler implements EventHandler<ActionEvent> {

        @Override
        public void handle(ActionEvent event) {
            stage.setScene(displayScene);
        }

    }

    private class ExitHandler implements EventHandler<ActionEvent> {

        @Override
        public void handle(ActionEvent event) {
            performIO(SAVE);
            Platform.exit();
        }

    }

}

public static class MainDisplay extends AnchorPane {

    private boolean running;

    public MainDisplay() {
        running = false;
        tower = new Tower();
        setUp();
    }

    private void setUp() {
        Color blue = new Color(34 / 255, 37 / 255, 47 / 255, 1.0);

        this.setBackground(new Background(new BackgroundFill(blue, null, null)));

        Background bkg = new Background(new BackgroundFill(null, null, null));
        Border menuBorder = new Border(new BorderStroke(Color.RED, BorderStrokeStyle.SOLID,
                new CornerRadii(10), null));

        Button home = new Button(Constants.HOME);
        home.setFont(Font.font("Times New Roman", 10));
        home.setTextFill(Color.WHITE);
        home.setBackground(bkg);
        home.setBorder(menuBorder);
        home.setOnAction(new HomeHandler());
        this.getChildren().add(home);
        AnchorPane.setTopAnchor(home, 10.0);
        AnchorPane.setRightAnchor(home, 10.0);
    }

    public void start() {
        running = true;
    }

    public boolean isRunning() {
        return running;
    }

    private class HomeHandler implements EventHandler<ActionEvent> {

        @Override
        public void handle(ActionEvent event) {
            stage.setScene(startScene);
        }

    }

}

}

Warning: some of the matchups may not be ideal with the essence of JavaFx, but they will do the work

Note: To use FX properly, it is suggested to use FXML and/or SceneBuilder.

Solution 2:[2]

I am not sure if it helps during converting, but I found that using SceneBuilder and fxmls makes building JavaFX apps much easier. Mainly, controller classes need to be added, view is built in .fxml . Just maybe it will be easier to build app from scratch in SceneBuilder, than tediously converting?

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1
Solution 2 Mykola