ZetCode

Kotlin OpenJFX

最后修改于 2024 年 1 月 29 日

本文介绍了如何在 Kotlin 中创建 OpenJFX GUI 应用程序。

OpenJFX是用于 JDK 的下一代客户端应用程序平台,适用于桌面和嵌入式系统。

应用程序

Application 是 OpenJFX 程序的主要类。它的 start 方法是应用程序的主入口点;它是系统准备就绪后调用的第一个方法。

一个应用程序由一个 Stage 和一个 Scene 组成。Stage 是顶级容器,是应用程序的主窗口。Scene 是 Stage 的视觉内容容器。Scene 的内容组织在场景图中。

场景图

场景图 是一个节点的分层树,表示应用程序用户界面的所有视觉元素。场景图中的单个元素称为节点。每个节点都是一个分支节点或叶节点。分支节点可以包含其他节点——它们的子节点。叶节点不包含其他节点。树中的第一个节点称为根节点;根节点没有父节点。

节点的具体实现包括图形图元、控件、布局管理器、图像或媒体。可以通过修改节点属性来操作场景。通过这种方式,我们可以对节点进行动画处理、应用效果、进行变换或更改其不透明度。

设置 OpenJFX

我们可以使用 Gradle 设置 OpenJFX。

plugins {
    kotlin("jvm") version "1.7.10"
    id("org.openjfx.javafxplugin") version "0.0.13"
}

我们添加 org.openjfx.javafxplugin 插件。

javafx {
    modules("javafx.controls")
}

我们配置 OpenJFX 应用程序。

简单示例

以下是一个简单的 OpenJFX 应用程序。

SimpleEx.kt
package com.zetcode

import javafx.application.Application
import javafx.scene.Scene
import javafx.scene.layout.StackPane
import javafx.stage.Stage

class SimpleEx : Application() {

    override fun start(stage: Stage) {

        val root = StackPane()
        val scene = Scene(root, 400.0, 300.0)

        stage.title = "Simple"
        stage.scene = scene
        stage.show()
    }
}

fun main() {
    Application.launch(SimpleEx::class.java)
}

该示例在屏幕上显示一个小窗口。

class SimpleEx : Application() {

每个 OpenJFX 程序都继承自 Application

override fun start(stage: Stage) {

Application 的 start 方法被重写。它是 OpenJFX 程序的主要入口点。它接收一个 Stage 作为其唯一参数。(Stage 是主应用程序窗口或区域。)

val root = StackPane()

StackPane 是用于组织节点的容器。它使用一个简单的布局管理器,将它的内容节点放置在一个从后到前的单一堆栈中。在我们的例子中,我们只想放置一个节点。

val scene = Scene(root, 400.0, 300.0)

Scene 是场景图中所有内容的容器。它将一个根节点作为其第一个参数。StackPane 是此场景图中的一个根节点。接下来的两个参数指定场景的宽度和高度。

stage.title = "Simple"

我们通过 title 属性设置窗口的标题。

stage.scene = scene

一个场景被添加到舞台。

stage.show()

show 方法在屏幕上显示窗口。

fun main() {
    Application.launch(SimpleEx::class.java)
}

我们使用 Application.launch 运行应用程序。

Simple example
图:简单示例

按钮控件

在下面的示例中,我们有一个 Button 控件。当我们点击按钮时,应用程序将终止。当按下并释放按钮时,将发送一个 ActionEvent

QuitButton.kt
package com.zetcode

import javafx.application.Application
import javafx.application.Platform
import javafx.event.EventHandler
import javafx.geometry.Insets
import javafx.scene.Scene
import javafx.scene.control.Button
import javafx.scene.layout.HBox
import javafx.scene.layout.StackPane
import javafx.stage.Stage

class QuitButton : Application() {

    override fun start(stage: Stage) {

        val hbox = HBox()
        hbox.padding = Insets(15.0, 0.0, 0.0, 15.0)

        val btn = Button("Quit")
        btn.prefWidth = 80.0
        btn.onAction = EventHandler { Platform.exit() }

        hbox.children.add(btn)

        val root = StackPane()
        root.style = "-fx-font-size: 1.2em"
        root.children.add(hbox)

        val scene = Scene(root, 400.0, 300.0)

        stage.title = "Quit button"
        stage.scene = scene
        stage.show()
    }
}

fun main() {
    Application.launch(QuitButton::class.java)
}

一个按钮控件被放置在窗口的左上角。一个事件处理程序被添加到按钮中。

val hbox = HBox()
hbox.padding = Insets(15.0, 0.0, 0.0, 15.0)

UI 元素的布局是通过布局管理器完成的。HBox 是一个简单的管理器,它在单行中布局控件。我们设置了一些填充,以便在我们的按钮和窗口边框之间留出一些空间。

val btn = Button("Quit")

创建了一个 Button 控件。我们提供它的文本。

btn.prefWidth = 80.0

我们增加了按钮的首选宽度,因为默认值太小了。

btn.onAction = EventHandler { Platform.exit() }

通过 onAction 属性,我们将一个事件处理程序插入到按钮中。当我们点击按钮时,提供的 lambda 表达式将被执行。Platform.exit 终止应用程序。

val root = StackPane()
root.style = "-fx-font-size: 1.2em"
root.children.add(hbox)

水平框被添加到 StackPane。我们通过 style 属性更改窗格的样式。字体大小已增加。默认值有点太小了。

Quit button
图:退出按钮

标签控件

Label 控件用于显示文本或图像。

Labels.kt
package com.zetcode

import javafx.application.Application
import javafx.geometry.Insets
import javafx.geometry.Pos
import javafx.scene.Scene
import javafx.scene.control.Label
import javafx.scene.image.Image
import javafx.scene.image.ImageView
import javafx.scene.layout.*
import javafx.scene.paint.Color
import javafx.scene.text.Font
import javafx.scene.text.FontPosture
import javafx.scene.text.FontWeight
import javafx.stage.Stage

class Labels : Application() {

    override fun start(stage: Stage) {

        val vbox = VBox(20.0)
        vbox.alignment = Pos.CENTER
        vbox.padding = Insets(20.0)

        val title = Label("Sid the sloth")
        title.font = Font.font("arial", FontWeight.BOLD,
            FontPosture.ITALIC, 22.0)

        val img = ImageView(Image("/images/sid.png"))
        val lbi = Label()
        lbi.graphic = img

        vbox.children.addAll(title, lbi)

        val root = StackPane()
        val bf = BackgroundFill(
            Color.valueOf("#358ae6"), CornerRadii.EMPTY, Insets.EMPTY
        )

        root.background = Background(bf)
        root.children.add(vbox)

        val scene = Scene(root)

        stage.title = "Labels"
        stage.scene = scene
        stage.show()
    }
}

fun main() {
    Application.launch(Labels::class.java)
}

在此程序中,我们使用标签来显示标题和 PNG 图像。

val vbox = VBox(20.0)
vbox.alignment = Pos.CENTER
vbox.padding = Insets(20.0)

这两个控件放置在垂直框中。

val title = Label("Sid the sloth")
title.font = Font.font("arial", FontWeight.BOLD,
    FontPosture.ITALIC, 22.0)

此标签显示文本。我们通过 font 属性设置一个新字体。

val img = ImageView(Image("/images/sid.png"))
val lbi = Label()
lbi.graphic = img

此标签显示一个图像。除了 Label,我们还使用 ImageViewImageImageView 通过 graphic 属性设置。

val bf = BackgroundFill(
    Color.valueOf("#358ae6"), CornerRadii.EMPTY, Insets.EMPTY
)

root.background = Background(bf)

为了更好的对比度,我们更改了窗口的背景颜色。

Labels
图:标签

复选框控件

CheckBox 是一个三态选择控件框,在选中时显示复选标记或勾号。该控件默认有两种状态:选中和未选中。setAllowIndeterminate 启用第三种状态:不确定。

CheckBoxEx.kt
package com.zetcode

import javafx.application.Application
import javafx.geometry.Insets
import javafx.scene.Scene
import javafx.scene.control.CheckBox
import javafx.scene.layout.HBox
import javafx.stage.Stage

class CheckBoxEx : Application() {

    override fun start(stage: Stage) {

        val root = HBox()
        root.padding = Insets(10.0, 0.0, 0.0, 10.0)

        val cbox = CheckBox("Show title")
        cbox.isSelected = true

        cbox.selectedProperty().addListener { _, _, newVal ->
            if (newVal) {
                stage.title = "CheckBox"
            } else {
                stage.title = ""
            }
        }

        root.children.add(cbox)

        val scene = Scene(root, 400.0, 250.0)

        stage.title = "CheckBox"
        stage.scene = scene
        stage.show()
    }

}

fun main() {
    Application.launch(CheckBoxEx::class.java)
}

该示例根据是否选中复选框来显示或隐藏窗口的标题。

val cbox = CheckBox("Show title")

创建了一个 CheckBox 控件。指定的文本是它的标签。

cbox.isSelected = true

由于窗口的标题默认可见,我们使用 isSelected 属性选择该控件。

cbox.selectedProperty().addListener { _, _, newVal ->
    if (newVal) {
        stage.title = "CheckBox"
    } else {
        stage.title = ""
    }
}

我们向已选属性添加了一个监听器。如果选中了 CheckBox,则 newVal 包含 true 值。根据该值,我们通过 title 属性更改窗口的标题。

CheckBox
图:复选框

滑块控件

Slider 是一个组件,允许用户通过在有界区间内滑动旋钮来以图形方式选择有效数值的连续或离散范围。

Slider 可以选择性地为它的值范围显示刻度线。刻度线使用 showTickMarks 属性设置。

SliderEx.kt
package com.zetcode

import javafx.application.Application
import javafx.geometry.Insets
import javafx.scene.Scene
import javafx.scene.control.Label
import javafx.scene.control.Slider
import javafx.scene.layout.HBox
import javafx.stage.Stage

class SliderEx : Application() {

    override fun start(stage: Stage) {

        val root = HBox()
        root.padding = Insets(10.0)
        root.spacing = 40.0

        val slider = Slider(0.0, 100.0, 0.0)
        slider.setMinSize(290.0, -1.0)
        slider.isShowTickMarks = true

        val label = Label("0")

        slider.valueProperty().addListener { _, _, newVal ->

            label.text = "${newVal.toInt()}"
        }

        root.children.addAll(slider, label)

        val scene = Scene(root, 400.0, 250.0)

        stage.title = "Slider"
        stage.scene = scene
        stage.show()
    }
}

fun main() {
    Application.launch(SliderEx::class.java)
}

从滑块中选择的值显示在相邻的标签组件中。

val slider = Slider(0.0, 100.0, 0.0)

Slider 是使用最小值、最大值和当前值作为参数创建的。

slider.setMinSize(290.0, -1.0)

我们使用 setMinSize 设置控件的最小尺寸。

slider.isShowTickMarks = true

isShowTickMarks 属性决定是否在滑块上绘制刻度线。

slider.valueProperty().addListener { _, _, newVal ->

    label.text = "${newVal.toInt()}"
}

我们为值属性的修改插入一个监听器。在 lambda 中,我们设置滑块的当前值到标签组件。

Slider
图:滑块

组合框控件

ComboBox 是一个组件,它结合了一个按钮或可编辑字段和一个下拉列表。用户可以从下拉列表中选择一个值,该下拉列表应用户请求出现。

如果我们将组合框设为可编辑,则组合框包含一个可编辑字段,用户可以在其中键入一个值。组合框通过 isEditable 属性设置为可编辑。

ComboBoxEx.kt
package com.zetcode

import javafx.application.Application
import javafx.collections.FXCollections
import javafx.geometry.Insets
import javafx.geometry.Pos
import javafx.scene.Scene
import javafx.scene.control.ComboBox
import javafx.scene.control.Label
import javafx.scene.layout.HBox
import javafx.scene.layout.StackPane
import javafx.stage.Stage

class ComboBoxEx : Application() {

    private lateinit var label: Label;

    override fun start(stage: Stage) {

        val hbox = HBox(40.0)
        hbox.padding = Insets(20.0)
        hbox.alignment = Pos.BASELINE_LEFT

        val distros = listOf(
            "Ubuntu", "Redhat", "Arch",
            "Debian", "Mint"
        )

        val combo = ComboBox(
            FXCollections.observableList(distros)
        )
        combo.valueProperty().addListener { _, _, newVal ->

            label.text = "$newVal"
        }

        combo.setMinSize(150.0, -1.0)

        label = Label()
        hbox.children.addAll(combo, label)

        val root = StackPane()
        root.style = "-fx-font-size: 1.5em"
        root.children.add(hbox)
        val scene = Scene(root, 400.0, 350.0)

        stage.title = "ComboBox"
        stage.scene = scene
        stage.show()
    }
}

fun main() {
    Application.launch(ComboBoxEx::class.java)
}

该程序包含一个组合框和一个标签。组合框包含一个 Linux 发行版名称列表。从组合框中选择的条目显示在相邻的标签中。

val distros = listOf(
    "Ubuntu", "Redhat", "Arch",
    "Debian", "Mint"
)

val combo = ComboBox(
    FXCollections.observableList(distros)
)

创建了一个 ComboBox。可观察列表允许监听器在发生更改时跟踪更改。

hbox.alignment = Pos.BASELINE_LEFT

使用基线选项,标签的文本与组合框的文本垂直对齐。

combo.valueProperty().addListener { _, _, newVal ->

    label.text = "$newVal"
}

我们向组合框的值属性添加了一个监听器。新值被设置为标签。

ComboBox
图:组合框

移动窗口

以下示例显示应用程序窗口在屏幕上的位置。

MoveWindowEx.kt
package com.zetcode

import javafx.application.Application
import javafx.geometry.Insets
import javafx.scene.Scene
import javafx.scene.control.Label
import javafx.scene.layout.VBox
import javafx.stage.Stage

class MoveWindowEx : Application() {

    private val lblX: Label = Label("")
    private val lblY: Label = Label("")

    override fun start(stage: Stage) {

        val vbox = VBox(10.0)
        vbox.padding = Insets(10.0);
        vbox.children.addAll(lblX, lblY);

        stage.xProperty().addListener { _, _, newVal -> lblX.text = "x: $newVal" }
        stage.yProperty().addListener { _, _, newVal -> lblY.text = "x: $newVal" }

        val scene = Scene(vbox, 450.0, 250.0)

        vbox.style = "-fx-font-size: 1.2em"

        stage.title = "Move window"
        stage.scene = scene
        stage.show()
    }
}

fun main() {
    Application.launch(MoveWindowEx::class.java)
}

该示例在两个标签控件中显示当前窗口坐标。要获取窗口位置,我们监听舞台的 xPropertyyProperty 的变化。

private val lblX: Label = Label("")
private val lblY: Label = Label("")

这两个标签显示应用程序窗口左上角的 x 和 y 坐标。

stage.xProperty().addListener { _, _, newVal -> lblX.text = "x: $newVal" }

xProperty 存储舞台在屏幕上的水平位置。我们添加一个监听器来监听属性的变化。每次修改属性时,我们检索新值并更新标签。

Moving window
图:移动窗口

形状

在下面的示例中,我们在画布上绘制形状。Canvas 是一种图像,可以使用 GraphicsContext 提供的一组图形命令在其上绘制。

Shapes.kt
package com.zetcode

import javafx.application.Application
import javafx.scene.Scene
import javafx.scene.canvas.Canvas
import javafx.scene.canvas.GraphicsContext
import javafx.scene.layout.Pane
import javafx.scene.paint.Color
import javafx.scene.shape.ArcType
import javafx.stage.Stage

class Shapes : Application() {

    override fun start(stage: Stage) {

        val root = Pane()

        val canvas = Canvas(500.0, 500.0)
        drawShapes(canvas.graphicsContext2D)

        root.children.add(canvas)

        val scene = Scene(root, 450.0, 350.0, Color.WHITESMOKE)

        stage.title = "Shapes"
        stage.scene = scene
        stage.show()
    }

    private fun drawShapes(gc: GraphicsContext) {

        gc.fill = Color.GRAY

        gc.fillOval(30.0, 30.0, 80.0, 80.0)
        gc.fillOval(150.0, 30.0, 120.0, 80.0)
        gc.fillRect(320.0, 30.0, 100.0, 100.0)
        gc.fillRoundRect(30.0, 180.0, 100.0, 100.0, 20.0, 20.0)
        gc.fillArc(150.0, 180.0, 100.0, 100.0, 45.0, 180.0, ArcType.OPEN)
        gc.fillPolygon(doubleArrayOf(290.0, 380.0, 290.0),
            doubleArrayOf(140.0, 300.0, 300.0), 3)
    }
}

fun main() {
    Application.launch(Shapes::class.java)
}

该示例使用图形上下文的填充方法绘制六个不同的形状。

private fun drawShapes(gc: GraphicsContext) {

GraphicsContext 是一个接口,通过它我们可以在画布上绘制。

gc.fill = Color.GRAY

这些形状以灰色绘制。

gc.fillOval(30.0, 30.0, 80.0, 80.0)
gc.fillOval(150.0, 30.0, 120.0, 80.0)

fillOval 方法绘制一个圆和一个椭圆。前两个参数是 x 和 y 坐标。第三个和第四个参数是椭圆的宽度和高度。

gc.fillRect(320.0, 30.0, 100.0, 100.0)

fillRect 使用当前的填充笔刷填充一个矩形。

gc.fillRoundRect(30.0, 180.0, 100.0, 100.0, 20.0, 20.0)

fillRoundRect 绘制一个矩形,其角是圆角的。该方法的最后两个参数是矩形角的弧宽和弧高。

gc.fillArc(150.0, 180.0, 100.0, 100.0, 45.0, 180.0, ArcType.OPEN)

fillArc 方法使用当前的填充笔刷填充一个弧形。最后三个参数是起始角度、角度延伸和闭合类型。

gc.fillPolygon(doubleArrayOf(290.0, 380.0, 290.0),
    doubleArrayOf(140.0, 300.0, 300.0), 3)

fillPolygon 方法使用当前设置的填充笔刷填充具有给定点的多边形。在我们的例子中,它绘制一个直角三角形。第一个参数是一个包含多边形点 x 坐标的数组,第二个参数是一个包含多边形点 y 坐标的数组。最后一个参数是构成多边形的点的数量。

Shapes
图:图形

贝塞尔曲线

一个 贝塞尔曲线 是一条三次线。它可以用 bezierCurveTo 在画布上绘制。

BezierCurve.kt
package com.zetcode

import javafx.application.Application
import javafx.scene.Scene
import javafx.scene.canvas.Canvas
import javafx.scene.canvas.GraphicsContext
import javafx.scene.layout.Pane
import javafx.scene.paint.Color
import javafx.stage.Stage

class BezierCurve : Application() {

    override fun start(stage: Stage) {

        val root = Pane()

        val canvas = Canvas(500.0, 500.0)
        drawCurve(canvas.graphicsContext2D)

        root.children.add(canvas)

        val scene = Scene(root, 450.0, 350.0, Color.WHITESMOKE)

        stage.title = "Bézier curve"
        stage.scene = scene
        stage.show()
    }

    private fun drawCurve(gc: GraphicsContext) {

        gc.stroke = Color.valueOf("#16567d")
        gc.lineWidth = 1.5

        gc.beginPath();
        gc.moveTo(40.0, 40.0);
        gc.bezierCurveTo(80.0, 240.0, 280.0, 90.0, 350.0, 300.0)

        gc.stroke()
    }
}

fun main() {
    Application.launch(BezierCurve::class.java)
}

该程序绘制一条贝塞尔曲线。

gc.stroke = Color.valueOf("#16567d")
gc.lineWidth = 1.5

该线将是蓝色的,宽度为 1.5 个单位。

gc.beginPath();
gc.moveTo(40.0, 40.0);
gc.bezierCurveTo(80.0, 240.0, 280.0, 90.0, 350.0, 300.0)

我们创建一个路径。首先,我们使用 moveTo 移动到一个点。然后我们使用 bezierCurveTo 绘制曲线。

gc.stroke()

路径使用 stroke 函数绘制。

Bézier curve
图:贝塞尔曲线

反射

Reflection 是一种效果,它在实际内容下方渲染对象的反射版本。

ReflectionEx.kt
package com.zetcode

import javafx.application.Application
import javafx.scene.Scene
import javafx.scene.effect.Reflection
import javafx.scene.layout.StackPane
import javafx.scene.paint.Color
import javafx.scene.text.Font
import javafx.scene.text.FontWeight
import javafx.scene.text.Text
import javafx.stage.Stage

class ReflectionEx : Application() {

    override fun start(stage: Stage) {

        val root = StackPane()

        val text = Text()
        text.text = "ZetCode";
        text.fill = Color.STEELBLUE;
        text.font = Font.font("Serif", FontWeight.BOLD, 60.0);

        val ref = Reflection()
        text.effect = ref;

        root.children.add(text);

        val scene = Scene(root, 400.0, 250.0)

        stage.title = "Reflection"
        stage.scene = scene
        stage.show()
    }
}

fun main() {
    Application.launch(ReflectionEx::class.java)
}

在程序中,我们显示一个反射文本。

val text = Text()
text.text = "ZetCode";
text.fill = Color.STEELBLUE;
text.font = Font.font("Serif", FontWeight.BOLD, 60.0);

创建了一个 Text 形状。我们定义它的颜色和字体。

val ref = Reflection()
text.effect = ref;

一个具有默认值的反射效果被应用于 Text

Reflection
图:反射

PathTransition 动画

PathTransition 沿着路径创建一个动画。动画通过更新节点的 translateXtranslateY 变量来执行。请注意,我们必须使用一个支持元素绝对定位的节点。

PathTransitionEx.kt
package com.zetcode

import javafx.animation.PathTransition
import javafx.application.Application
import javafx.scene.Scene
import javafx.scene.layout.Pane
import javafx.scene.paint.Color
import javafx.scene.shape.Circle
import javafx.scene.shape.CubicCurveTo
import javafx.scene.shape.MoveTo
import javafx.scene.shape.Path
import javafx.stage.Stage
import javafx.util.Duration

class PathTransitionEx : Application() {

    override fun start(stage: Stage) {

        val root = Pane()

        val path = Path()
        path.elements.add(MoveTo(20.0, 120.0))
        path.elements.add(
            CubicCurveTo(
                180.0, 60.0,
                250.0, 340.0, 420.0, 240.0
            )
        )

        val circle = Circle(20.0, 120.0, 10.0)
        circle.fill = Color.CADETBLUE

        val ptr = PathTransition()

        ptr.duration = Duration.seconds(6.0)
        ptr.delay = Duration.seconds(2.0)
        ptr.path = path
        ptr.node = circle
        ptr.cycleCount = 2
        ptr.isAutoReverse = true
        ptr.play()

        root.children.addAll(path, circle)

        val scene = Scene(root, 450.0, 350.0)

        stage.title = "Path transition"
        stage.scene = scene
        stage.show()
    }
}

fun main() {
    Application.launch(PathTransitionEx::class.java)
}

该程序使用 PathTransition 沿路径移动一个圆。动画在初始延迟 2 秒后开始。它由两个周期组成。动画被反转;也就是说,圆从起点移动到终点,然后返回。

val root = Pane()

我们使用 Pane 作为我们的根节点。它支持动画所需的绝对定位。

val path = Path()
path.elements.add(MoveTo(20.0, 120.0))
path.elements.add(
    CubicCurveTo(
        180.0, 60.0,
        250.0, 340.0, 420.0, 240.0
    )
)

在这里,我们定义一个 Path,动画对象将沿着该路径移动。

var circle = new Circle(20, 120, 10);
circle.setFill(Color.CADETBLUE);

我们在动画中移动一个圆对象。

val ptr = PathTransition()

创建了一个 PathTransition 对象。

ptr.duration = Duration.seconds(6.0)

duration 属性设置动画的持续时间。

ptr.delay = Duration.seconds(2.0)

delay 属性设置动画的初始延迟。

ptr.path = path
ptr.node = circle

我们设置动画的路径和目标节点。

ptr.cycleCount = 2

我们的动画有两个周期;它使用 cycleCount 属性设置。

ptr.isAutoReverse = true

使用 isAutoReverse 属性,我们反转动画的方向;圆圈移动回起始位置。

ptr.play()

最后,play 方法播放动画。

PathTransition
图:PathTransition

饼图

饼图是一个圆形图表,它被分成切片以说明数字比例。可以使用 PieChart 创建它。

PieChartEx.kt
package com.zetcode

import javafx.application.Application
import javafx.collections.FXCollections
import javafx.collections.ObservableList
import javafx.scene.Scene
import javafx.scene.chart.PieChart
import javafx.scene.layout.HBox
import javafx.stage.Stage

class PieChartEx : Application() {

    override fun start(stage: Stage) {

        val root = HBox()
        val scene = Scene(root, 450.0, 330.0)

        val pieChartData: ObservableList<PieChart.Data> =
            FXCollections.observableArrayList(
                PieChart.Data("Apache", 52.0),
                PieChart.Data("Nginx", 31.0),
                PieChart.Data("IIS", 12.0),
                PieChart.Data("LiteSpeed", 2.0),
                PieChart.Data("Google server", 1.0),
                PieChart.Data("Others", 2.0)
            )

        val pieChart = PieChart(pieChartData)
        pieChart.title = "Web servers market share (2016)"

        root.children.add(pieChart)

        stage.title = "PieChart"
        stage.scene = scene
        stage.show()
    }
}

fun main() {
    Application.launch(PieChartEx::class.java)
}

在该程序中,创建一个饼图以显示 Web 服务器的市场份额。

val pieChartData: ObservableList<PieChart.Data> =
    FXCollections.observableArrayList(
        PieChart.Data("Apache", 52.0),
        PieChart.Data("Nginx", 31.0),
        PieChart.Data("IIS", 12.0),
        PieChart.Data("LiteSpeed", 2.0),
        PieChart.Data("Google server", 1.0),
        PieChart.Data("Others", 2.0)
    )

饼图数据项使用 PieChart.Data 创建。

val pieChart = PieChart(pieChartData)

使用 PieChart 类创建饼图。

PieChart
图:饼图

来源

OpenJFX 文档

本文介绍了使用 Kotlin 和 OpenJFX 进行 UI 开发。

作者

我叫 Jan Bodnar,是一位充满激情的程序员,拥有丰富的编程经验。自 2007 年以来,我一直在撰写编程文章。到目前为止,我已撰写了 1,400 多篇文章和 8 本电子书。我拥有超过十年的编程教学经验。

列出 所有 Kotlin 教程