首页 > 解决方案 > 关于 Kotlin 的一些基本问题

问题描述

我正在尝试学习 Kotlin 和 TornadoFX,我正在使用这个存储库

目前的想法是该应用程序将显示三行 7 个按钮。每个按钮代表一个已知或未知的字母。如果字母是已知的,它会显示在按钮上。如果字母未知,按钮将显示索引 (0-20)。

我通过创建(使用 Java 认为我确定)一个包含 21 个元素的全局数组来做到这一点。每个元素都以 null 开头。我在主应用程序中定义了这个,使用伴随结构:

class InteractiveClientApp : App(MainView::class) {
    companion object {
        var knownLetters = arrayOfNulls<String>(21)
    }

然后在 App 构造函数中,我用值初始化了一些随机元素,只是为了看看这是否可行(它不可行)。

override fun init() {
    knownLetters[4] = "T"
    knownLetters[9] = "G"
    knownLetters[17] = "Z"
}

然后在 LettersGridView 中,我在 knownLetters 数组上使用 forEachIndexed,因此我可以访问数组中的元素及其索引。

import jcn.deduce.client.InteractiveClientApp.Companion.knownLetters


class LettersGridView : View() {
    override val root = gridpane {

            knownLetters.forEachIndexed { index, element ->

                if (index == 0 || index % 7 == 0) {
                    row {
                        button(element?.toString() ?: index.toString()) {
                            useMaxWidth = true
                            gridpaneConstraints {
                                marginBottom = 10.0
                            }
                        }
                    }
                } else {
                    button(element?.toString() ?: index.toString()) {
                        useMaxWidth = true
                        gridpaneConstraints {
                            marginBottom = 10.0
                        }
                    }
                }
            }
        }
    }

实际发生的是三个按钮而不是预期的 21,并且按钮上的值始终是索引,而不是字母值。显示的索引也是 20、7 和 14。不是我在数组中设置元素时使用的三个。所以我在那里遗漏了一些东西。

另外我认为我没有正确理解这一点:

 button(element?.toString() ?: index.toString()) {
                        useMaxWidth = true
                        gridpaneConstraints {
                            marginBottom = 10.0
                        }
                    }

我想说的是“如果元素值不为空,则使用元素值,否则使用索引的字符串值。这是行不通的,因为按钮上只有索引,而不是字母。

我注意到如果我离开元素上的 .toString() ,我会收到一个错误,即按钮需要字符串,而不是字符串?。这似乎有点类似于 Java 和 String vs Optional < String >。但是,当我添加 toString() 时,我收到一个 IDE 警告,指出 toString() 是多余的。

如果我脱掉尾随?总的来说,我得到了一个干净的编译,但仍然只有三个按钮呈现,它们的标签是索引,而不是元素。

所以我很确定我在途中迷路了,谁能解释为什么我的程序不工作?

此外,当我调试应用程序时,我总是以两个进程结束。我不明白为什么,但这就是 IntelliJ 的样子:

在此处输入图像描述

这是正常的吗?

标签: kotlintornadofx

解决方案


您的 init 函数正在工作,您可以通过将条目 20、7 或 14 的初始化更改为字母来确认这一点,下次运行时您应该会看到一个字母。

至于您的主要问题,您看到 20、7 和 14 的原因是因为在本节中:

if (index == 0 || index % 7 == 0) {
    row {
        button(element?.toString() ?: index.toString()) {
            useMaxWidth = true
            gridpaneConstraints {
                marginBottom = 10.0
            }
        }
    }
}

您正在添加一个带有单个按钮的行,这些按钮将是 0、7 和 14(因为它们都是 == 0 % 7)。这意味着您只会添加三行,每行都有一个按钮。您可能会对为什么它说 20 而不是 0 感到困惑……嗯,这是因为下一节:

else {
    button(element?.toString() ?: index.toString()) {
        useMaxWidth = true
        gridpaneConstraints {
            marginBottom = 10.0
        }
    }
}

也在添加按钮,但没有添加到任何行上(注意这些按钮如何不在行 { } lambda 内)。这意味着所有这些按钮都将被添加到彼此顶部的网格窗格中,包括第一个 0 按钮。最后一个要添加的按钮是 20,因此为什么你看到 20,它覆盖了 0!

以下是如何解决此问题的示例:

val rowSize = 7
val rows = knownLetters.toList().chunked(rowSize)
rows.forEachIndexed { rowIndex, elements ->
    row {
        elements.forEachIndexed { buttonIndex, element ->
            val displayIndex = rowSize * rowIndex + buttonIndex
            button("${element ?: displayIndex}") {
                useMaxWidth = true
                gridpaneConstraints {
                    marginBottom = 10.0
                }
            }
        }
    }
}

这需要 Kotlin 库的“分块”方法将 21 大小的数组分成三个大小为 7 的列表。然后您可以循环遍历(您必须使用这种方法将显示索引拼凑在一起)为每个列表创建一个新行(3 个列表组成 3 行),同时在行的 lambda 内的嵌套循环中创建按钮。

这里要带走的关键是,并非所有按钮都添加到行 { } lambda 中。

至于双进程问题,如果我使用这样的 main 方法运行应用程序,我就没有这个问题:

fun main(args: Array<String>) {
    launch<InteractiveClientApp>(args)
}

希望这可以帮助!


推荐阅读