我正在尝试学习Kotlin和TornadoFX,并且正在this repository上工作
当前的想法是该应用将显示3行的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
}
}
我要说的是:“如果元素值不为null,则使用元素值,否则使用index的字符串值。这不起作用,因为按钮仅在其上具有索引,从不字母。
我注意到,如果我没有在元素上使用.toString(),则会收到一个错误,提示按钮期望使用String而不是String?这似乎有点类似于Java和String与Optional
如果我脱掉尾随的?总共,我得到了一个干净的编译器,但是仍然只渲染了三个按钮,它们的标签是索引,而不是元素。
所以我很确定自己在此过程中迷路了,有人可以解释为什么我的程序无法正常工作吗?
此外,在调试应用程序时,我总是会经历两个过程。我不明白为什么,但这是IntelliJ的样子:
这正常吗?
答案 0 :(得分:2)
您的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行中添加了所有按钮。
对于双重处理问题,如果我使用类似这样的主要方法运行应用程序,则不会出现此问题:
fun main(args: Array<String>) {
launch<InteractiveClientApp>(args)
}
希望这会有所帮助!