kotlin - 关于 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 的样子:
这是正常的吗?
解决方案
您的 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)
}
希望这可以帮助!
推荐阅读
- c# - 未生成 ASP.NET MVC Identity 默认控制器和视图
- python - 带有 flat=true 的 Values_list 仍然显示
- json - 肥皂响应 XML 到 Json - 春季启动
- python - 如何将 python 与 qr 扫描仪设备一起使用?
- javascript - onclick 将链接到另一个页面上的特定部分的 img
- spss - 创建团队人口统计变量 - 相似性/不相似性
- fast-ai - 如何将 fastai 表格模型应用于新数据?
- sublimetext3 - Sublime codeintel 自动完成有时不起作用
- react-native - 如何在 React-native 中动态添加和删除表行
- javascript - vuetify v-bind 内联样式值不更新