Build a simple calculator with TornadoFX


TornadoFX is a ui framework for Kotlin on top of JavaFX.

It leverages the functional capabilities of Kotlin to create an easy to use ui framework with JavaFX as stable backbone.

In this tutorial we will create a simple calculator that will allow us to add, subtract and multiply integers.

Setting up

For this tutorial we will use gradle with kotlin dsl to build the test application.

mkdir kotlin_tornado
cd kotlin_tornado
gradle init --dsl kotlin 

The gradle build file is quiet extensive but I think the comments are explaining enough.

plugins {
    application
    kotlin("jvm") version "1.3.0"

    // We need the javafx plugin since java 11
    id("org.openjfx.javafxplugin") version "0.0.7"
}
dependencies {
    compile(kotlin("stdlib"))

    // Add the tornadofx dependency
    compile("no.tornado:tornadofx:1.7.17")
}
repositories {
    mavenCentral()
}

javafx {

    // Declare the javafx modules we need to use
    modules("javafx.controls")
}

application {

    // Declare the main class for the application plugin
    mainClassName = "de.klg71.tornado.MainApp"
}

// Set the jvmTarget to 1.8 to support inlining
tasks.withType<org.jetbrains.kotlin.gradle.tasks.KotlinCompile> { kotlinOptions.jvmTarget = "1.8" }

We should be able to execute it without any error:

gradle clean build

Starting with the HelloWorld example

At first we will create a small window with a “HelloWorld” label.

// Define application with main View `Main`
class MainApp : App(Main::class)

// Define the view to display
class Main : View() {

    // override the root view with our container with the label within
    override val root = hbox {
        // use the tornado kotlin dsl to add a label and set the text
        label {
            text = "Hello World"
        }
    }
}

We can exectute it with the gradle task run:

gradle run

Now there should appear a small window with our “Hello World” message.

Design a calculator

We will again use the Tornado Kotlin DSL to create our window.

We create a form and a a fieldset for our first and second number.

class Main : View() {

    // Define the content
    override val root = hbox {
        hbox {
            form {
                // Every field must be contained in a fieldset
                fieldset {
                    text = "Calculator"

                    field {
                        // Set the caption for this field
                        text = "Number 1"
                    }
                    field {
                        text = "Number 2"
                    }
                }

            }
        }
    }
}

If we run this with gradle run we will get simple form window where we can enter two numbers.

At next we will add buttons and a result field to our form:

class Main : View() {

    // Define the content
    override val root = hbox {
        hbox {
            form {
                // Every field must be contained in a fieldset
                fieldset {
                    // Title of our formular
                    text = "Calculator"

                    field {
                        // Set the caption for this field
                        text = "Number 1"
                    }
                    field {
                        text = "Number 2"
                    }
                    // Add the buttonbar with our three operations
                    hbox {
                        spacing = 2.0

                        button {
                            text = "add"
                        }
                        button {
                            text = "subtract"
                        }
                        button {
                            text = "multiply"
                        }
                    }
                    // Add a result field
                    field {
                        text = "Result"
                    }
                }

            }
        }
    }
}

Value Binding

Now that our view is complete we need to add some functionality. To get and set the values of a form, TornadoFX uses a value binding mechanism.

You can define a property and then assign this property to a field. Then each change in the property results in the field value beeing updated.

We define three properties for number1, number2 and the result:

class Main : View() {
    
    // Declare our three properties
    private val number1 = SimpleIntegerProperty()
    private val number2 = SimpleIntegerProperty()
    private val result = SimpleIntegerProperty()

    override val root = hbox {
        hbox {
            form {
                fieldset {
                    text = "Calculator"

                    field {
                        text = "Number 1"
                        // Assign the property to the textfield
                        textfield().bind(number1)
                    }
                    field {
                        text = "Number 2"
                        // Assign the property to the textfield
                        textfield().bind(number2)
                    }

                    // ...
                    // Buttons ommitted
                    // ...

                    field {
                        text = "Result"
                        // Assign the property to the label
                        label().bind(result)
                    }
                }
            }
        }
      }
    }

React on button clicks

Now the only thing left to do is to add some functionality to the buttons. For this purpose buttons have a method called action with the function to execute as parameter:

class Main : View() {

    private val number1 = SimpleIntegerProperty()
    private val number2 = SimpleIntegerProperty()
    private val result = SimpleIntegerProperty()

    override val root = hbox {
        hbox {
            form {
                fieldset {
                    text = "Calculator"

                    // ... Fields ommitted ...
                    hbox {
                        spacing = 2.0

                        button {
                            text = "add"
                            // Call the action method with the add method from the Main class
                            action(::add)
                        }
                        button {
                            text = "subtract"
                        }
                        button {
                            text = "multiply"
                        }
                    }
                    // ... Fields ommitted ...

                }

            }
        }
    }

    private fun add() {

        // Assign a new value to result which immediately changes the value on the screen
        result.value = number1.value + number2.value
    }

}

Finish the app:

Below you can see the complete code for our application with the multiply and subtract functions added.

package de.klg71.tornado

import javafx.beans.property.SimpleIntegerProperty
import tornadofx.*


class MainApp : App(Main::class)

class Main : View() {

    private val number1 = SimpleIntegerProperty()
    private val number2 = SimpleIntegerProperty()
    private val result = SimpleIntegerProperty()

    override val root = hbox {
        hbox {
            form {
                fieldset {
                    text = "Calculator"

                    field {
                        text = "Number 1"
                        textfield().bind(number1)
                    }
                    field {
                        text = "Number 2"
                        textfield().bind(number2)
                    }
                    hbox {
                        spacing = 2.0

                        button {
                            text = "add"
                            action(::add)
                        }
                        button {
                            text = "subtract"
                            action(::subtract)
                        }
                        button {
                            text = "multiply"
                            action(::multiply)
                        }
                    }
                    field {
                        text = "Result"
                        label().bind(result)

                    }

                }

            }
        }
    }

    private fun add() {
        result.value = number1.value + number2.value
    }

    private fun subtract() {
        result.value = number1.value - number2.value
    }

    private fun multiply() {
        result.value = number1.value * number2.value
    }

}

You can execute this with “gradle run” and try out the calculator. this with “gradle run” and try out the calculator.

Calculator

Wrapping up

We used TornadoFX to create a simple calculator app. This app is able to add, subtract and multiply to integer numbers and diplay the result.

You can find the whole code on Github: kotlin_tornadofx