How bad is it when you actually EXPECT your own article to be boring? I’ll do my best to say something interesting.

My plan this morning—hold on a second while I start some music—my plan is to find a small example of a TornadoFX window, and try to bend it into something like what I think I want for the “UI” for this little game. So if you know how to make windows in Kotlin, with or without TornadoFX, you’re far ahead of me. Even I find it hard to believe how long it has been since I did things like windows. Codea and Lua are so much fun, with so little messing about like creating windows. Just spaceships and asteroids and aliens.

But today, I need a window with some stuff in it, connected to whatever you connect to to make it do things. I might have one here somewhere … but no. None of my current projects, eleven of them, mostly failures, includes a simple window. I really want a prototype to work from. I think GeePaw must have what I need on his repo somewhere … but no.

There’s nothing for it but to find an example and work through it.

I do have a simple window in the main files. Let’s review those. This is HelloApplication:

class MainView: View() {
    override val root: Parent = pane()
}

class HelloApplication : App(MainView::class) {
}

fun main() {
    launch<HelloApplication>()
}

Right, looks familiar. I think there in MainView is where we put our widgets. And here is HelloController:

import javafx.fxml.FXML
import javafx.scene.control.Label

class HelloController {
    @FXML
    private lateinit var welcomeText: Label

    @FXML
    private fun onHelloButtonClick() {
        welcomeText.text = "Welcome to JavaFX Application!"
    }
}

I think that’s not supposed to be like that. I don’t really want to have FXML going on up in this baby. I’ll see about deleting that whole file shortly.

I try this change to my view:

import tornadofx.label

class MainView: View() {
    override val root: Parent = pane {
        label("Hello Ron")
    }
}

I get a tiny little window saying “Hello Ron”. This is incredibly good progress. To make this work I had to add an import. For some reason my imports here have each item separately. I’ll go with that. If I import the whole thing I’ll surely be confused and probably so will IDEA.

I’ve found an example to follow. Seems simple enough if I ignore the pages of info you have to work through just to get set up.

The example has hbox. I try that, and IDEA finally imports all of TornadoFX:

import tornadofx.*

class MainView: View() {
    override val root: Parent = hbox {
        label("Hello Ron")
    }
}

Still a tiny window. Trekking through the example, ignoring the CSS bits. Obviously I need to insert some details. I do have a place to look for some of that I think.

I’m going back to pane, in part to follow some code I found on GeePaw’s repo and in part because I know I don’t want an hbox.

class MainView: View() {
    override val root: Parent = pane {
        minWidth = 400.0
        minHeight = 200.0
        label("Hello Ron")
    }
}

Now we’re cooking with gas1! I have a window of a credible sort of size, with “Hello Ron” in it. Excuse me while I mess around with some things without telling you every boring step.

Woot! Take small wins. Here’s my amazing view now:

var myLabel: Label by singleAssign()

class MainView: View() {
    override val root: Parent = vbox {
        minWidth = 400.0
        minHeight = 200.0
        myLabel = label("Hello Ron")
        button("Press me") {
            action { someonePressedMe() }
        }
    }
}

fun someonePressedMe() {
    println("pressed")
    myLabel.text = "I saw that!"
}

What I’ve learned is that you can create a var that will contain whatever control you create in the builder DSL, giving it a var name of your own and assigning it as done with myLabel, And, if you happen to know the control’s innards, or can trek your way through IDEA’s ideas, you can change it.

My window now opens like this:

window with "Hello Ron" and a Button "Press me"

When I click the button, the label changes to “I saw that!”. Thus, woot!

window with "I saw that!" and the same Button.

This may seem trivial, and it is, but it is also an important milestone. Meterstone? Footstone? Angstromstone? Let’s reflect.

Reflection

When I started out at 0800, I really didn’t know at all how to create a window with active things in it. I’d seen it done, but never done it. And now I have a closed loop between my code and a window. I know there is tons to do now, and that I’ll have to figure out a decent structure with models and controllers and all that jazz, but it seems possible now, and before this, I was just staring into the Void of Ignorance.

And all it took was something like three different web sites to get me through it. No actual hand-holding, which I’d have preferred. Er, I mean pairing or mobbing. Seriously: it’s much better learning with someone who knows a bit more than you do, rather than reading some article like this one, that goes on and on, delving into corners and pits that you’re not remotely interested in, seemingly always going somewhere that isn’t what you want, then suddenly turning in yet another random direction, sometimes never getting where you’d like to go and other times deferring it for so long that by the time it does arrive at a desirable station you’ve long since fallen asleep.

Has that ever happened to you? Perhaps not recently.

But I am serious: connecting a simple window layout and a button press changing a text thing. This is almost exactly what my little app needs. More to learn, but now I have a couple of hooks upon which to hang my thoughts.

I want to emphasize this. My internal state has changed because of a tiny trivial bit of code. Going in, I had no idea what to do, and no code to edit. Now I have some code to improve … and that makes all the difference!

This is so good that I’m going to break and entertain myself in some different way. See you next article!



  1. Yes, people really used to say that. Now we should probably be cooking with renewable hydrogen or something. Or not cooking. It’s so complicated these days.