CS 346 (W23)
Toggle Dark/Light/Auto mode Toggle Dark/Light/Auto mode Toggle Dark/Light/Auto mode Back to homepage

JavaFX

We’re using Kotlin with the Java Virtual Machine (JVM) ecosystem, so we’ll discuss some toolkits that are available in that ecosystem.

Java launched in 1996, with AWT as its first GUI framework. AWT is a heavyweight toolkit that provided a thin abstraction layer over the system-specific widgets provided by OS vendors i.e. it provided wrappers for UI components that were built into the OS. However, this tight integration to the OS meant that AWT behaved very differently across different operating systems, which ran counter to Sun’s original goals of having a single cohesive toolkit that ran equally well on all platforms.

Swing was originally part of the Java Foundation Classes, and replaced the AWT in 1997. Unlike AWT, Swing is a lightweight toolkit: Swing components draw themselves using the Java2D Graphics Library, which makes Swing applications consistent across platforms. This also means that Swing can support a broader range of components, including some that aren’t directly supported by the OS. In other words, lightweight toolkits provide some tangible benefits:

  • The largest collection of widgets, not limited to just the subset that can be assumed to be present on each OS.
  • Consistency in how widgets behave, since they are designed as a set.
  • An OS independent look-and-feel.

JavaFX was originally designed by Sun Microsystems in 2008 as a replacement for the Java AWT and Swing toolkits, and was designed to compete directly with Adobe Flash/Flex and similar web toolkits. In 2010, Oracle released JavaFX into the community as part of the OpenJDK initiative. The open source version of JavaFX is currently maintained by Gluon and the community.

JavaFX is an imperative toolkit, where the programmer describes the layout and how it should be managed in code (and XML). [This contrasts with a declarative toolkit like Jetpack Compose, where the programmer describes a layout and the system reflects state in that layout].

JavaFX is a lightweight toolkit that runs well on Windows, Mac, Linux. It provides a native look-and-feel on each platform, and even supports hardware acceleration! It’s not included with the JRE, but because it’s open source, we can distrbute the libraries with our applications.

Setup

Although JavaFX can be installed from the main JavaFX site, the recommended way to bundle these libraries into your application is to add it to your Gradle configuration file. Gradle will then download and install JavaFX as-needed.

In your project’s build.gradle file, make the following changes to include the javafxplugin and related settings in the javafx block.

import org.jetbrains.kotlin.gradle.tasks.KotlinCompile

plugins {
    application
    kotlin("jvm") version "1.6.20"
    id("org.openjfx.javafxplugin") version "0.0.13"
    id("org.beryx.jlink") version "2.25.0"
}

group = "net.codebot"
version = "1.0.0"

val compileKotlin: KotlinCompile by tasks
val compileJava: JavaCompile by tasks
compileJava.destinationDirectory.set(compileKotlin.destinationDirectory)

repositories {
    mavenCentral()
}

dependencies {
    testImplementation(kotlin("test"))
}

tasks.test {
    useJUnitPlatform()
}

tasks.withType<KotlinCompile> {
    kotlinOptions.jvmTarget = "1.8"
}

application {
    mainModule.set("calculator")
    mainClass.set("calculator.Main")
}

javafx {
    // version is determined by the plugin above
    version = "18.0.2"
    modules = listOf("javafx.controls", "javafx.graphics")
}

// https://stackoverflow.com/questions/74453018/jlink-package-kotlin-in-both-merged-module-and-kotlin-stdlib
jlink {
    forceMerge("kotlin")
}

In your Gradle menu in IntelliJ, press “Sync” to load the changes, and the JavaFX libraries should be loaded. If you expand the “External Libraries” in the Project view, you can see the JavaFX libraries have been installed:

JavaFX libraries

Example: HelloFX

The following application shows how to create a simple window with some graphics. Athough longer than our console version of “Hello Kotlin”, it accomplishes quite a lot with minimal code. We’ll discuss this in further detail below.

class App: Application() {
  override fun start(stage:Stage?) { 
    val image = Image("java.png", 175.0, 175.0) 
    val imageView = ImageView(image)
    val label = Label( 
      System.getProperty("java.vendor")
      + System.getProperty("java.version") + "\n"
        + System.getProperty("javafx.version"))

    val box = VBox(imageView, label) 
    VBox.setMargin(label, Insets(10.0)) 

    val scene = Scene(box, 175.0, 225.0) 
    stage.setResizable(false) 
    stage.setScene(scene) 
    stage.show() 
  }
} 

JavaFX Window

This is actually pretty impressive when you realize that we have just created:

  • A resizable window with min/max/restore buttons
  • A titlebar and content centred in the window.
  • A UI that will inherit the appearance of any platform where it runs. Execute this on Windows, and the buttons will have a standard appearance and positioning for that platform!