Uruchamianie aplikacji JavaFX w Kotlinie

Zastanawialiście się kiedyś, czy da się uruchomić aplikację JavaFX w Kotlinie? Da się i – wbrew pozorom – nie jest to wcale trudne. Załóżmy, że mamy klasę JavaFX, taką jak poniżej:

package assets;

import javafx.application.Application;
import javafx.application.Platform;
import javafx.scene.Scene;
import javafx.scene.layout.StackPane;
import javafx.stage.Stage;

public class ClassTemplate extends 

Application {
   
    @Override
    public void init() {
    }

    @Override
    public void start(Stage stage) {
        try {
            StackPane root = new StackPane();
            Scene scene = new Scene(root, 300, 200);
            stage.setScene(scene);
            stage.setTitle(this.getClass().getName());
            stage.setOnCloseRequest(e -> Platform.exit());
            stage.show();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    @Override
    public void stop() {
    }

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

Teraz wystarczy użyć automatycznego tłumaczam dostępnego w IntelliJ IDEA. Po poprawieniu Int na Double i uporządkowaniu sekcji importów, otrzymamy kod taki jak poniżej:

package assets

import javafx.application.Application
import javafx.application.Platform
import javafx.event.EventHandler
import javafx.scene.Scene
import javafx.scene.layout.StackPane
import javafx.stage.Stage

class ClassTemplate : Application() {
    override fun init() {}
    override fun start(stage: Stage) {
        try {
            val root = StackPane()
            val scene = Scene(root, 300.0, 

200.0)
            stage.scene = scene
            stage.title = this.javaClass.name
            stage.onCloseRequest = EventHandler { Platform.exit() }
            stage.show()
        } catch (e: Exception) {
            e.printStackTrace()
        }
    }

    override fun stop() {}

    companion object {
        @JvmStatic
        fun main(args: Array<String>) {
            launch(*args)
        }
    }
}

To jednak nie wystarczy – jeśli spróbujemy ten kod uruchomić, otrzymamy błąd:

Powodem jest błędne tłumaczenie metody main uruchamiającej aplikację. Po poprawieniu kodu klasa powinna wyglądać tak:

package assets

import javafx.application.Application
import javafx.application.Platform
import javafx.event.EventHandler
import javafx.scene.Scene
import javafx.scene.layout.StackPane
import javafx.stage.Stage

class ClassTemplate : Application() {
    override fun init() {}
    override fun start(stage: Stage) {
        try {
            val root = StackPane()
            val scene = Scene(root, 300.0, 

200.0)
            stage.scene = scene
            stage.title = this.javaClass.name
            stage.onCloseRequest = EventHandler { Platform.exit() }
            stage.show()
        } catch (e: Exception) {
            e.printStackTrace()
        }
    }

    override fun stop() {}

    companion object {
        @JvmStatic
        fun main(args: Array<String>) {
            launch(ClassTemplate::class.java, *args)
        }
    }
}

Zauważcie, że zmienił się tylko parametr metody launch(). Teraz kod powinien uruchomić się poprawnie. Oczywiście dla porządku metodę main możemy wyłączyć poza klasę, tak jak widać poniżej:

package assets

import javafx.application.Application
import javafx.stage.Stage
import javafx.scene.layout.StackPane
import javafx.scene.Scene
import java.lang.Exception
import kotlin.jvm.JvmStatic

class ClassTemplate2 : Application() {
    override fun init() {}
    override fun start(stage: Stage) {
        try {
            val root = StackPane()
            stage.scene = Scene(root, 300.0, 200.0)
            stage.show()
        } catch (e: Exception) {
            e.printStackTrace()
        }
    }

    override fun stop() {}
}
fun main(args: Array<String>) {
    Application.launch(ClassTemplate2::class.java, *args)
}

W ten sposób można oczywiście „przetłumaczyć” dowolną klasę JavaFX na Kotlina.