[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"project-7348":3},{"id":4,"name":5,"fullName":6,"owner":7,"repo":5,"description":8,"homepage":9,"htmlUrl":10,"language":11,"languages":10,"totalLinesOfCode":10,"stars":12,"forks":13,"watchers":14,"openIssues":15,"contributorsCount":16,"subscribersCount":16,"size":16,"stars1d":16,"stars7d":17,"stars30d":18,"stars90d":16,"forks30d":16,"starsTrendScore":16,"compositeScore":19,"rankGlobal":10,"rankLanguage":10,"license":20,"archived":21,"fork":22,"defaultBranch":23,"hasWiki":21,"hasPages":22,"topics":24,"createdAt":10,"pushedAt":10,"updatedAt":30,"readmeContent":31,"aiSummary":32,"trendingCount":16,"starSnapshotCount":16,"syncStatus":18,"lastSyncTime":33,"discoverSource":34},7348,"tornadofx","edvin\u002Ftornadofx","edvin","Lightweight JavaFX Framework for Kotlin","",null,"Kotlin",3636,270,4,186,0,1,2,29.3,"Apache License 2.0",true,false,"master",[25,26,27,28,5,29],"desktop","javafx","kotlin","rcp","ui-kit","2026-06-12 02:01:38","![TornadoFX Logo](graphics\u002Ftornado-fx-logo.png?raw=true \"TornadoFX\")\n# TornadoFX\n\nJavaFX Framework for Kotlin\n\n## (This project is no longer maintained)\n\n[![Travis CI](https:\u002F\u002Ftravis-ci.org\u002Fedvin\u002Ftornadofx.svg)](https:\u002F\u002Ftravis-ci.org\u002Fedvin\u002Ftornadofx)\n[![Maven Central](https:\u002F\u002Fmaven-badges.herokuapp.com\u002Fmaven-central\u002Fno.tornado\u002Ftornadofx\u002Fbadge.svg?cachebust)](https:\u002F\u002Fsearch.maven.org\u002F#search|ga|1|no.tornado.tornadofx)\n[![Apache License](https:\u002F\u002Fimg.shields.io\u002Fbadge\u002Flicense-Apache%20License%202.0-blue.svg)](http:\u002F\u002Fwww.apache.org\u002Flicenses\u002FLICENSE-2.0)\n\n**Important: TornadoFX is not yet compatible with Java 9\u002F10**\n\nOracle is intending to decouple JavaFX from the JDK. We will wait\nuntil the decoupled JavaFX is available and stable before upgrading TornadoFX to support\nit. As of now there is little value and significant effort involved in updating to JDK 9\u002F10,\nwhile there will be an enormous value in updating to the decoupled version.\n\n## Features\n\n- Supports both MVC, MVP and their derivatives\n- Dependency injection\n- Type safe GUI builders\n- Type safe CSS builders\n- First class FXML support\n- Async task execution\n- EventBus with thread targeting\n- Hot reload of Views and Stylesheets\n- OSGi support\n- REST client with automatic JSON conversion\n- Zero config, no XML, no annotations\n\n## Important version note\n\nTornadoFX requires Kotlin 1.1.2 and jvmTarget 1.8. Make sure you update your IDE plugins (Kotlin + TornadoFX).\n\nAfter updating IntelliJ IDEA, make sure your Kotlin target version is 1.1 (Project Settings -> Modules -> Kotlin -> Language Version \u002F API Version)\n\nRemember to update your build system to configure the `jvmTarget` as well.\n\nFor Maven, you add the following configuration block to `kotlin-maven-plugin`:\n\n```xml\n\u003Cconfiguration>\n    \u003CjvmTarget>1.8\u003C\u002FjvmTarget>\n\u003C\u002Fconfiguration>\n```\n\nFor Gradle, it means configuring the `kotlinOptions` of the Kotlin compilation task:\n\n```gradle\ncompileKotlin {\n    kotlinOptions.jvmTarget= \"1.8\"\n}\n```\n\nFailing to do so will yield errors about the compiler not being able to inline certain calls.\n\nYou also need a full rebuild of your code after a version upgrade. If you run into trouble, try to clean caches and restart IDEA (File -> Invalidate caches \u002F Restart).\n \n## Getting started\n\n- [Screencasts](https:\u002F\u002Fwww.youtube.com\u002Fuser\u002FMrEdvinsyse)\n- [Guide](https:\u002F\u002Fdocs.tornadofx.io\u002F) We are gradually migrating all information from the Wiki into the Guide\n- [KDocs](https:\u002F\u002Ftornadofx.io\u002Fdokka\u002Ftornadofx\u002Ftornadofx\u002Findex.html)\n- [Wiki](https:\u002F\u002Fgithub.com\u002Fedvin\u002Ftornadofx\u002Fwiki)\n- [Slack](https:\u002F\u002Fkotlinlang.slack.com\u002Fmessages\u002Ftornadofx\u002Fdetails\u002F)\n- [Stack Overflow](http:\u002F\u002Fstackoverflow.com\u002Fquestions\u002Fask?tags=tornadofx)\n- [Documentation](https:\u002F\u002Fgithub.com\u002Fedvin\u002Ftornadofx\u002Fwiki\u002FDocumentation) \n- [IntelliJ IDEA Plugin](https:\u002F\u002Fgithub.com\u002Fedvin\u002Ftornadofx-idea-plugin) \n- [Example Application](https:\u002F\u002Fgithub.com\u002Fedvin\u002Ftornadofx-samples) \n- [Maven QuickStart Archetype](https:\u002F\u002Fgithub.com\u002Fedvin\u002Ftornadofx-quickstart-archetype) \n- [Changelog](CHANGELOG.md)\n\n### Generate a quickstart application with Maven\n\n```bash\nmvn archetype:generate -DarchetypeGroupId=no.tornado \\\n  -DarchetypeArtifactId=tornadofx-quickstart-archetype \\\n  -DarchetypeVersion=1.7.20\n```\n\n### Add TornadoFX to your project\n\n#### Maven\n\n```xml\n\u003Cdependency>\n    \u003CgroupId>no.tornado\u003C\u002FgroupId>\n    \u003CartifactId>tornadofx\u003C\u002FartifactId>\n    \u003Cversion>1.7.20\u003C\u002Fversion>\n\u003C\u002Fdependency>\n```\n\n### Gradle\n\n```groovy\nimplementation 'no.tornado:tornadofx:1.7.20'\n```\n\n### Snapshots are published to Sonatype\n\nConfigure your build environment to use snapshots if you want to try out the latest features:\n\n```xml\n \u003Crepositories>\n   \u003Crepository>\n     \u003Cid>snapshots-repo\u003C\u002Fid>\n     \u003Curl>https:\u002F\u002Foss.sonatype.org\u002Fcontent\u002Frepositories\u002Fsnapshots\u003C\u002Furl>\n     \u003Creleases>\u003Cenabled>false\u003C\u002Fenabled>\u003C\u002Freleases>\n     \u003Csnapshots>\u003Cenabled>true\u003C\u002Fenabled>\u003C\u002Fsnapshots>\n   \u003C\u002Frepository>\n \u003C\u002Frepositories>\n```\n\nSnapshots are published every day at GMT 16:00 if there has been any changes.\n\n### What does it look like? (Code snippets)\n\nCreate a View\n\n```kotlin\nclass HelloWorld : View() {\n    override val root = hbox {\n        label(\"Hello world\")\n    }\n}\n```\n\nStart your application and show the primary `View` and add a type safe stylesheet\n    \n```kotlin\nimport javafx.scene.text.FontWeight\nimport tornadofx.*\n\nclass HelloWorldApp : App(HelloWorld::class, Styles::class)\n\nclass Styles : Stylesheet() {\n    init {\n        label {\n            fontSize = 20.px\n            fontWeight = FontWeight.BOLD\n            backgroundColor += c(\"#cecece\")\n        }    \n    }    \n}\n```\n> Start app and load a type safe stylesheet\n\nUse [Type Safe Builders](https:\u002F\u002Fgithub.com\u002Fedvin\u002Ftornadofx\u002Fwiki\u002FType-Safe-Builders) to quickly create complex user interfaces\n\n```kotlin\nclass MyView : View() {\n    private val persons = FXCollections.observableArrayList(\n            Person(1, \"Samantha Stuart\", LocalDate.of(1981,12,4)),\n            Person(2, \"Tom Marks\", LocalDate.of(2001,1,23)),\n            Person(3, \"Stuart Gills\", LocalDate.of(1989,5,23)),\n            Person(3, \"Nicole Williams\", LocalDate.of(1998,8,11))\n    )\n\n    override val root = tableview(persons) {\n        column(\"ID\", Person::id)\n        column(\"Name\", Person::name)\n        column(\"Birthday\", Person::birthday)\n        column(\"Age\", Person::age)\n        columnResizePolicy = SmartResize.POLICY\n    }\n}\n```\n\n**RENDERED UI**\n\n![](https:\u002F\u002Fi.imgur.com\u002FAGMCP8S.png)\n\nCreate a Customer model object that can be converted to and from JSON and exposes both a JavaFX Property and getter\u002Fsetter pairs:\n\n```kotlin\nimport tornadofx.getValue\nimport tornadofx.setValue\n\nclass Customer : JsonModel {\n    val idProperty = SimpleIntegerProperty()\n    var id by idProperty\n\n    val nameProperty = SimpleStringProperty()\n    var name by nameProperty\n\n    override fun updateModel(json: JsonObject) {\n        with(json) {\n            id = int(\"id\") ?: 0\n            name = string(\"name\")\n        }\n    }\n\n    override fun toJSON(json: JsonBuilder) {\n        with(json) {\n            add(\"id\", id)\n            add(\"name\", name)\n        }\n    }\n}\n```\n    \nCreate a controller which downloads a JSON list of customers with the REST api:\n\n```kotlin\nclass HelloWorldController : Controller() {\n    val api : Rest by inject()\n    \n    fun loadCustomers(): ObservableList\u003CCustomer> = \n        api.get(\"customers\").list().toModel() \n}\n```\n    \nConfigure the REST API with a base URI and Basic Authentication:\n    \n```kotlin\nwith (api) {\n    baseURI = \"http:\u002F\u002Fcontoso.com\u002Fapi\"\n    setBasicAuth(\"user\", \"secret\")\n}\n```\n    \nLoad customers in the background and update a TableView on the UI thread:\n\n```kotlin\nrunAsync {\n    controller.loadCustomers()\n} ui {\n    customerTable.items = it\n}\n```\n\nLoad customers and apply to table declaratively:\n\n```kotlin\ncustomerTable.asyncItems { controller.loadCustomers() }\n```\n\nDefine a type safe CSS stylesheet:\n\n```kotlin\nclass Styles : Stylesheet() {\n    companion object {\n        \u002F\u002F Define css classes\n        val heading by cssclass()\n        \n        \u002F\u002F Define colors\n        val mainColor = c(\"#bdbd22\")\n    }\n\n    init {\n        heading {\n            textFill = mainColor\n            fontSize = 20.px\n            fontWeight = BOLD\n        }\n        \n        button {\n            padding = box(10.px, 20.px)\n            fontWeight = BOLD\n        }\n\n        val flat = mixin {\n            backgroundInsets += box(0.px)\n            borderColor += box(Color.DARKGRAY)\n        }\n\n        s(button, textInput) {\n            +flat\n        }\n    }\n}\n```\n\nCreate an HBox with a Label and a TextField with type safe builders:\n\n```kotlin\nhbox {\n    label(\"Hello world\") {\n        addClass(heading)\n    }\n    \n    textfield {\n        promptText = \"Enter your name\"\n    }\n}\n```\n    \nGet and set per component configuration settings:\n    \n```kotlin\n\u002F\u002F set prefWidth from setting or default to 200.0\nnode.prefWidth(config.double(\"width\", 200.0))\n\n\u002F\u002F set username and age, then save\nwith (config) {\n    set(\"username\", \"john\")\n    set(\"age\", 30)\n    save()\n}\n```\n    \nCreate a `Fragment` instead of a `View`. A `Fragment` is not a `Singleton` like `View` is, so you will\ncreate a new instance and you can reuse the Fragment in multiple ui locations simultaneously.\n     \n```kotlin\nclass MyFragment : Fragment() {\n    override val root = hbox {\n    }\n}\n```\n     \nOpen it in a Modal Window:\n                   \n```kotlin\nfind\u003CMyFragment>().openModal()\n``` \n         \nLookup and embed a `View` inside another `Pane` in one go\n           \n```kotlin\nadd\u003CMyFragment>()\n```\n\nInject a `View` and embed inside another `Pane`\n       \n```kotlin\nval myView: MyView by inject()\n \ninit {\n    root.add(myFragment)\n}\n```\n\nSwap a View for another (change Scene root or embedded View)\n\n```kotlin\nbutton(\"Go to next page\") {\n    action {\n        replaceWith\u003CPageTwo>(ViewTransition.Slide(0.3.seconds, Direction.LEFT)\n    }\n}\n```\n\nOpen a View in an internal window over the current scene graph\n\n```kotlin\nbutton(\"Open\") {\n    action {\n        openInternalWindow\u003CMyOtherView>()\n    }\n}\n```\n","TornadoFX 是一个轻量级的用于 Kotlin 的 JavaFX 框架。它支持 MVC 和 MVP 架构模式及其变体，提供了依赖注入、类型安全的 GUI 和 CSS 构建器、异步任务执行以及事件总线等功能。此外，TornadoFX 还具备热重载视图和样式表的能力，并且内置了 REST 客户端，支持自动 JSON 转换。该框架特别适合需要快速开发桌面应用程序的场景，尤其是当开发者希望利用 Kotlin 语言特性来简化 JavaFX 应用程序构建过程时。尽管目前 TornadoFX 不再维护并且不兼容 Java 9\u002F10，但对于基于 JDK 8 的项目来说，它仍然是一个非常有价值的选择。","2026-06-11 03:11:54","top_language"]