Use Javafx from the JVM part of a Kotlin multiplatform project?

I’m working on a multiplatform project that has the following modules:

kotlin {
    //commonMain is implicitly declared
    jvm()
    linuxX64("linux") { ... }
    jvm("gui")

    sourceSets {
        guiMain {
            dependsOn jvmMain
        }
    }
}

The project is a text-based tool with all of the logic implemented in the commonMain module. The jvm and linux modules provide the Java and Linux integration respectively.

I now want to create a simple GUI on top of this, which is why I created another module called guiMain that will implement this. It depends on jvmMain for obvious reasons. I started building something using Swing, and that works fine.

However, I wanted to take this opportunity to experiment with JavaFX, and that’s where I’m having trouble. Reading the guide on the JavaFX web site (https://openjfx.io/openjfx-docs/#gradle) gives me some instructions but when I try to follow them, it doesn’t work.

The Gradle file is properly parsed, but my compilation stops at the first attempt to access any of the javafx classes. It seems as though they have not been made available to the guiMain module. That doesn’t surprise me, since I’m never actually declaring which module uses JavaFX in the gradle configuration file.

It’s very unclear to me how I’m supposed to use this, and none of the documentation I’ve read gives me any insight either. I experimented with putting the javafx { ... } declaration inside the module definition, but that didn’t work either.

Is it even possible to do this, and if so, how?

I am not sure, that adding a sourceset to mpp is the thing you need. It is much easier to create additional jvm-only gradle module and add a dependency on jvm-flavored part of your project as on a library. Then you can use javafx/tornadofx as in java-only project. It is possible to create javafx-based module in mpp, but the build is much more complicated. See an example here: https://github.com/mipt-npm/dataforge-vis/blob/dev/dataforge-vis-spatial/build.gradle.kts.

Thank you very much. This got me on the right track I think. I managed to create a subproject called gui, and I added the following to settings.gradle:

include ":gui"

The subproject now contains a stub JavaFX project which runs fine.

There is a problem though. Is it possible to have the gui module depend on the jvmMain module in the parent project?

I tried the following, which according to my reading of the documentation should be the right thing. Note that the root project name (the multiplatform project which I described in my previous post) is called array.

dependencies {
    implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk8"
    implementation project(':array:jvmMain')
}

When I try to load the gradle definition I get the following error:

A problem occurred evaluating project ':gui'.
> Project with path ':array:jvmMain' could not be found in project ':gui'.

Do you have suggestions what can be done?

You do not need to add dependency on the sourceset. project(':array') will suffice. Kotlin-jvm plagin can detect proper sourceset dependencies.You need to declare proper artifact name only if you add dependency on something from a repository.

I see. But then how can I tell the gui subproject that the code references some other modules? If I understand what you’re saying, then the dependencies section should not be used for this purpose.

In the root project I achieved this by specifying the dependsOn option in the sourceSets section. But when I try to do the same in my gui subproject, I run into issues.

sourceSets {
    main {
        dependsOn jvmMain
    }
}

I get the following error:

A problem occurred evaluating project ':gui'.
> Could not get unknown property 'jvmMain' for source set 'main' of type org.gradle.api.internal.tasks.DefaultSourceSet.

You put dependency on gradle module, say array. Gradle plugin finds that given project is mpp and puts a dependency on an appropriate source set. If you need something non-standard, you need to see gradle dependency configuration documentation.

Thank you very much for the explanation. I managed to get it to work by moving the main project to a subproject (so that there is no code in the root project).

I’m still not sure if it’s supposed to be possible to have the multiplatform project as a root project with a subproject depending on the root project. But, it works right now.

you may want to checkout https://tornadofx.io/ wrt kotlin and javafx.
and also https://korlibs.soywiz.com/ which provides some multiplatform UI support