Vítejte v dalším díle věnovaném jazyku Kotlin, kde si ukážeme, jak psát nabušené GUÍ-tka založené na JavaFX za pomocí výborného frameworku TornadoFX. Náš výsledek bude vypadat takto a celé nakódění nám nezabere déle jak 30 minut:

Zrovna jsem se vrátil z kite kurzu a jako obvykle si potřebuju vyúčtovat proplacení benzínu za cestu na spot a zpět. Zatímco jiní lidé by si udělali nějakou šablonku v Excelu, já jsem si na to rovnou napsal malou GUI aplikaci v Kotlinu, protože to až tolik nezabolí a výsledek prostě stojí za to! 🙂 Nejde však pouze o samotné GUI, ale taky o krásnou reaktivní funkcionalitu, resp. TornadoFX je natolik skvělé, že možnost psát GUI o sofistikovanosti nějaké soudobé ReactJS aplikace na webovém frontendu nyní přechází i na desktop. Bude potřeba jediná závislost (mimo klasický Kotlin základ), a sice:
<dependency>
<groupId>no.tornado</groupId>
<artifactId>tornadofx</artifactId>
<version>1.7.15</version>
</dependency>
A nyní již zbývá napsat následujících 85 řádků kódu do jediného souboru:
package com.svetylkovo.fuelrefund
import javafx.application.Application
import javafx.beans.property.SimpleDoubleProperty
import javafx.beans.property.SimpleObjectProperty
import javafx.beans.property.SimpleStringProperty
import tornadofx.*
import kotlin.math.roundToInt
class Spot(val name: String, val distance: Double) {
override fun toString() = name
}
class FuelRefund : View("Fuel Refund App") {
private val spots = listOf(
Spot("Příbor", 24.0),
Spot("Veselák", 101.0)
).observable()
private val selectedSpot = SimpleObjectProperty<Spot>()
private val consumption = SimpleDoubleProperty(0.0)
private val distance = SimpleDoubleProperty(0.0)
private val fuelPrice = SimpleDoubleProperty(0.0)
private val result = SimpleStringProperty("")
override val root = vbox {
prefWidth = 400.0
prefHeight = 400.0
form {
fieldset("Input parameters") {
field("Spot:") {
combobox(selectedSpot, spots)
}
field("Distance:") {
textfield(distance)
label("km")
}
field("Consumption:") {
textfield(consumption)
label("1l/100km")
}
field("Fuel price (1l):") {
textfield(fuelPrice)
label("Kč")
}
}
fieldset("Result:") {
textarea(result)
}
button("Copy to clipboard").action {
clipboard.putString(result.get())
}
}
}
private fun computePrice() {
val consumption = consumption.get()
val distance = distance.get()
val fuelPrice = fuelPrice.get()
val priceResult = (consumption/100) * distance * fuelPrice
result.set("($consumption/100) * $distance * $fuelPrice = ${priceResult.roundToInt()} Kč")
}
init {
selectedSpot.onChange { distance.set(it?.distance ?: 0.0) }
distance.onChange { computePrice() }
consumption.onChange { computePrice() }
fuelPrice.onChange { computePrice() }
selectedSpot.set(spots.first())
}
}
class FuelRefundApp : App(FuelRefund::class) {
companion object {
@JvmStatic
fun main(args: Array<String>) {
Application.launch(FuelRefundApp::class.java)
}
}
}