1. 简介

本文将介绍 TornadoFX 是什么,如何在 Oracle JDK 和 OpenJDK 上进行环境搭建。我们还会解析其架构组成,并快速浏览一些常用控件的使用方式。

在开始前,建议你对 JavaFX 有一定了解——虽然不是必须的。因为 TornadoFX 本质上是 Kotlin 的 JavaFX 框架,它充分利用了 Kotlin 的语言特性,比如声明式 UI、依赖注入、委托属性、扩展函数等,极大提升了开发效率和代码可读性。

⚠️ 需要特别注意:TornadoFX 目前尚未支持 Java 9 及以上版本,因此推荐使用 Java 8。这一点在项目选型时务必留意,避免踩坑。


2. 环境搭建

本节将演示如何从零开始配置一个 TornadoFX 项目,分别基于 Maven 和 Gradle。

2.1. OpenJDK

如果你使用的是 Linux 系统,大概率会用 OpenJDK。但要注意:OpenJDK 默认不包含 JavaFX 模块,所以需要手动引入,配置相对复杂。

✅ 正确做法:

  • 升级 OpenJDK 至 11 或更高版本
  • 使用 javafxplugin 插件管理 JavaFX 依赖

Gradle 配置(build.gradle)

plugins {
    id 'org.jetbrains.kotlin.jvm' version '1.5.10'
    id 'org.openjfx.javafxplugin' version '0.0.8'
    id 'application'
}

compileKotlin {
    kotlinOptions.jvmTarget = "11"
}

compileTestKotlin {
    kotlinOptions.jvmTarget = "11"
}

javafx {
    version = "11.0.2"
    modules = ['javafx.controls', 'javafx.graphics']
}

repositories {
    mavenCentral()
}

dependencies {
    implementation platform('org.jetbrains.kotlin:kotlin-bom')
    implementation 'org.jetbrains.kotlin:kotlin-stdlib-jdk8'
    implementation "no.tornado:tornadofx:1.7.20"
}

📌 提示:

Maven 配置(pom.xml)

先定义版本属性:

<properties>
    <tornadofx.version>1.7.20</tornadofx.version>
</properties>

添加核心依赖:

<dependency>
    <groupId>no.tornado</groupId>
    <artifactId>tornadofx</artifactId>
    <version>1.7.20</version>
</dependency>

由于 JavaFX 被拆分为多个模块,需显式引入以下组件:

<!-- JavaFX 基础模块 -->
<dependency>
    <groupId>org.openjfx</groupId>
    <artifactId>javafx-base</artifactId>
    <version>17-ea+11</version>
</dependency>

<!-- 控件模块(ListView, MenuBar 等) -->
<dependency>
    <groupId>org.openjfx</groupId>
    <artifactId>javafx-controls</artifactId>
    <version>17-ea+11</version>
</dependency>

同时添加 JavaFX Maven 插件用于运行:

<plugins>
    <plugin>
        <groupId>org.openjfx</groupId>
        <artifactId>javafx-maven-plugin</artifactId>
        <version>0.0.3</version>
        <configuration>
            <mainClass>MyApp</mainClass>
        </configuration>
    </plugin>
</plugins>

⚠️ 注意:若项目使用模块化(module-info.java),需在 src/main/kotlin 下创建 module-info.kt

module TFXSAMPLE {
    requires javafx.controls;
    requires javafx.graphics;
    requires javafx.base;
    requires tornadofx;
    requires kotlin.stdlib;
    exports com.example.demo.app to javafx.graphics, tornadofx;
    exports com.example.demo.view to tornadofx;
}

2.2. Oracle JDK

Oracle JDK 自带完整 JavaFX 支持,因此配置极其简单——无需额外引入 JavaFX 模块。

Gradle 配置

repositories {
    mavenCentral()
}

dependencies {
    implementation 'no.tornado:tornadofx:1.7.20'
}

Maven 配置

<dependency>
    <groupId>no.tornado</groupId>
    <artifactId>tornadofx</artifactId>
    <version>1.7.20</version>
</dependency>

✅ 总结:
| JDK 类型 | 是否需手动引入 JavaFX | 配置复杂度 | |--------------|------------------------|------------| | OpenJDK | ✅ 是 | ⚠️ 高 | | Oracle JDK | ❌ 否 | ✅ 低 |


3. 应用基础结构

和所有 Java/Kotlin 应用一样,TornadoFX 需要一个主类作为入口点。

创建 app 包并定义 MyApp 类,继承自 App,并通过构造函数指定初始视图:

class MyApp : App(HelloWorld::class)

这里的 HelloWorld::class 即为启动后默认加载的视图类。


4. 视图类(View)

视图(View)负责 UI 展示逻辑与节点布局,类似于 JavaFX 中的 Stage 或 Scene。但与 FXML 不同,TornadoFX 使用纯 Kotlin 代码构建 UI,带来类型安全和编译时检查的优势。

创建 view 包并添加 HelloWorld 类:

import tornadofx.*

class HelloWorld : View() {
    override val root = hbox {
        label("Hello world")
    }
}

关键点说明:

  • import tornadofx.* 必须存在,否则 IDE 无法识别 DSL 扩展函数
  • hbox 是水平布局容器,label 为其子节点
  • root 是视图的根节点,必须被重写

运行效果如下:

tfx before


5. 样式处理(Styling)

TornadoFX 支持类型安全的 CSS 样式定义,可通过独立样式类或内联方式设置。

方式一:独立样式类

创建 Styles 类统一管理样式:

class Styles : Stylesheet() {
    init {
        label {
            padding = box(10.px)
            fontSize = 20.px
            fontWeight = FontWeight.BOLD
        }
    }
}

然后在应用类中注册该样式表:

class MyApp : App(MainView::class, Styles::class)

效果呈现:

tfx after

方式二:内联样式(Inline Style)

适用于局部覆盖或临时调整:

label("Hello world") {
    style {
        padding = box(10.px)
        fontSize = 20.px
        fontWeight = FontWeight.BOLD
    }
}

✅ 内联样式的优先级高于全局样式,适合做动态样式覆盖。


6. 视图注入(View Injection)

TornadoFX 内建依赖注入机制,支持松耦合组件通信。

有两种注入方式:

方法 行为特点 推荐场景
find() 立即获取单例实例 简单引用,无循环依赖
inject() 懒加载代理,首次访问时初始化 复杂组件、存在循环依赖

推荐使用 inject(),优势在于:

  • ✅ 支持循环依赖
  • ✅ 实现懒加载,提升启动性能

示例代码:

class SampleView : View() {
    private val headerView = find(HeaderView::class)
    private val footerView: FooterView by inject()

    override val root = borderpane {
        top = headerView.root
        bottom = footerView.root
    }
}

7. 控制器(Controller)

遵循关注点分离原则,业务逻辑应与 UI 解耦。TornadoFX 提供 Controller 类实现这一模式。

典型用法:

  1. 创建 Controller 类继承 Controller
  2. 在 View 中通过 by inject() 注入控制器
  3. 绑定事件触发业务逻辑
class SampleView : View() {
    private val controller: SampleController by inject()
    private val input = SimpleStringProperty()

    override val root = form {
        fieldset {
            field() {
                textfield(input)
            }
            button("Post") {
                action {
                    controller.postApi(input.value)
                    input.value = ""
                }
            }
        }
    }
}

class SampleController : Controller() {
    fun postApi(inputValue: String) {
        println("Doing backend stuff with $inputValue")
    }
}

✅ 这种分层结构便于单元测试和维护,是大型项目的推荐实践。


8. 总结

本文带你快速入门 TornadoFX,涵盖环境搭建、视图定义、样式管理、依赖注入与控制器使用等核心内容。

虽然还有很多高级特性未涉及(如 REST 客户端、表格绑定、状态管理等),但已足够让你上手开发桌面应用。

📌 延伸学习资源:

对于熟悉 Kotlin 的开发者来说,TornadoFX 是构建现代 JavaFX 应用的高效选择,值得一试。


原始标题:Introduction to TornadoFX