我正在使用TornadoFX框架和Kotlin创建一个简单的桌面应用程序,让用户单击按钮,选择USFM文件,并将该USFM文件的内容吐出到文本区域。我已经掌握了基础知识,但我想通过分离出我的按钮逻辑来提升代码。目前,我的唯一视图定义了单击按钮时要执行的操作的逻辑。代码如下所示:
import tornadofx.*
import javafx.scene.layout.BorderPane
import javafx.stage.FileChooser
import javafx.scene.control.Button
import javafx.scene.control.Label
import javafx.scene.control.TextArea
import java.io.File
class AppView : View() {
override val root: BorderPane by fxml()
val chooseFile: Button by fxid<Button>()
val fileName: Label by fxid<Label>()
val textArea: TextArea by fxid<TextArea>()
lateinit var fileChosen: File
init {
title = "USFM Viewer"
root.lookup(".button").setOnMouseClicked {
var fileFilter = arrayOf(FileChooser.ExtensionFilter("USFM files", "*.usfm"))
fileChosen = chooseFile("Select a USFM File", fileFilter, FileChooserMode.Single)[0]
fileName.text = fileChosen.name
val fileParser = USFMFileParser(fileChosen)
val printout = fileParser.readFile(fileChosen)
textArea.text = printout.joinToString()
}
}
}
我的初步计划是创建自己的Button类,该类继承自Button类,并使用自己的方法覆盖或初始化以处理单击事件。目标是简单地在我的视图文件中声明按钮,而不必为它定义额外的逻辑。我似乎在努力完成这项工作。
这是我的自定义按钮类的原型:
import javafx.scene.control.Button
import javafx.stage.FileChooser
import tornadofx.*
import java.io.File
class ChooseFileButton: Button(){
val fileFilter = arrayOf(FileChooser.ExtensionFilter("USFM File", "*.usfm"))
val files: List<File>
get() = chooseFile("Select a USFM File", fileFilter, FileChooserMode.Single)
init {
action { println(this.files[0].name) }
}
}
此外,这是我的FXML文件,以提供有关我阶段元素的更多上下文:
<?import javafx.scene.control.Label?>
<?import javafx.scene.control.Button?>
<?import javafx.scene.control.TextArea?>
<?import javafx.scene.layout.BorderPane?>
<?import javafx.scene.control.ScrollPane?>
<?import javafx.scene.layout.FlowPane?>
<BorderPane id="appview"
xmlns="http://javafx.com/javafx/8.0.40"
xmlns:fx="http://javafx.com/fxml/1"
prefHeight="635"
prefWidth="500">
<top>
<FlowPane>
<Button fx:id="chooseFile" id="chooseFile" text="Choose File..." />
<Label fx:id="fileName" id="fileName" text="No File Chosen"/>
</FlowPane>
</top>
<center>
<ScrollPane>
<TextArea fx:id="textArea" id="textArea"></TextArea>
</ScrollPane>
</center>
</BorderPane>
有没有人有关于如何将按钮逻辑与视图分开的提示,建议,链接等?这甚至可能吗?
答案 0 :(得分:0)
无需为此创建Button子类。只需在t.Invoke(() => t.Name = "Group Scrapper");
上创建一个扩展功能,按照您想要的方式配置按钮,并为每个按钮调用该功能一次。您还应该考虑使用FXML来使用类型安全构建器,这样可以使这更方便,更不用说类型安全了。
以下是此类函数的示例,它允许您指定解析器,过滤并将文件加载到目标字符串属性中。还有一个默认的解析器,它只是按原样加载文件。
ButtonBase
以下是使用函数的完整类型安全构建器示例:
fun ButtonBase.loadFile(target: Property<String>,
parser: (File) -> String = { Files.readAllBytes(it.toPath()).toString(StandardCharsets.UTF_8) },
filters: Array<FileChooser.ExtensionFilter>) {
action {
chooseFile(text, filters, FileChooserMode.Single).firstOrNull()?.let {
target.value = parser.invoke(it)
}
}
}
如果你真的想坚持FXML(也许你只想输入东西:),你可以这样称呼:
class FileChooserTest : View() {
val fileContent = SimpleStringProperty()
override val root = borderpane {
center {
textarea(fileContent)
}
bottom {
buttonbar {
button("Select a USFM File") {
loadFile(fileContent, filters = arrayOf(FileChooser.ExtensionFilter("USFM File", "*.usfm")))
}
}
}
}
}
可以按照您喜欢的方式扩展class AppView : View("USFM Viewer") {
override val root: BorderPane by fxml()
val chooseFile: Button by fxid<Button>()
val textArea: TextArea by fxid<TextArea>()
init {
chooseFile.loadFile(textArea.textProperty(), filters = arrayOf(FileChooser.ExtensionFilter("USFM File", "*.usfm")))
}
}
功能,例如返回所选文件,为文件选择器对话框指定单独的标题等。
另一个提示:在您的示例代码中,您使用loadFile
委托找到了该按钮,但之后又执行了另一个by fxml()
来再次找到该按钮。您应该重复使用已经找到的按钮。