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:

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
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);
}
}
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); } }
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
Int na
Double
Double i uporządkowaniu sekcji importów, otrzymamy kod taki jak poniżej:

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
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)
}
}
}
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) } } }
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
main uruchamiającej aplikację. Po poprawieniu kodu klasa powinna wyglądać tak:

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
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)
}
}
}
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) } } }
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()
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:

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
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)
}
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) }
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.