controls - ScalaFX:是否可以在应用程序对象以外的对象中定义控件?
问题描述
我想要完成的是:拥有一个ScalaFX应用程序,其中包含一些很好的有序s ,object
称为Buttons
,等等,以保持一切正常有序。Labels
Checkboxes
这里有一个小例子来说明我的意思:
package ButtonsAndLabel
import scalafx.Includes._
import scalafx.application.JFXApp
import scalafx.scene.Scene
import scalafx.scene.control.{ Button, Label }
import scalafx.event.ActionEvent
object Main extends JFXApp {
stage = new JFXApp.PrimaryStage {
title = "Test-Program"
scene = new Scene(300, 200) {
val label = new Label("Nothing happened yet") {
layoutX = 20
layoutY = 20
}
val button1 = new Button("Button 1") {
layoutX = 20
layoutY = 50
onAction = (e: ActionEvent) => {
label.text = "B1 klicked"
}
}
val button2 = new Button("Button 2") {
layoutX = 20
layoutY = 80
onAction = (e: ActionEvent) => {
label.text = "B2 klicked"
}
}
content = List(label, button1, button2)
}
}
}
这段代码显示了一个带有标签和两个按钮的窗口,这些按钮更改了标签的文本。
这很好用。
但是当我的代码随着更多控件的增加而增长时,事情就会变得一团糟。
这就是为什么我试图将控件转移到其他object
s(在不同的文件中)。我已将标签放入一个名为Labels
:
package ButtonsAndLabel
import scalafx.scene.control.Label
import scalafx.event.ActionEvent
object Labels {
val label = new Label("Nothing happened yet") {
layoutX = 20
layoutY = 20
}
}
当我将其导入主文件时
import Labels.label
一切正常。
但后来我尝试将按钮放入一个Buttons
对象中:
package ButtonsAndLabel
import scalafx.scene.control.Button
import scalafx.event.ActionEvent
import Labels.label
object Buttons {
val button1 = new Button("Button 1") {
layoutX = 20
layoutY = 50
onAction = (e: ActionEvent) => {
label.text = "B1 klicked"
}
}
val button2 = new Button("Button 2") {
layoutX = 20
layoutY = 80
onAction = (e: ActionEvent) => {
label.text = "B2 klicked"
}
}
}
当我尝试编译时,这会带来错误消息:
[error] found : scalafx.event.ActionEvent => Unit [error] required: javafx.event.EventHandler[javafx.event.ActionEvent] [error] onAction = (e: ActionEvent) => {
现在我被困住了,因为我不知道任何Java。
有谁知道我正在尝试做的事情是否可能?
到目前为止,我还没有在网上找到任何关于此的信息。这个问题并没有阻止我编写我想要的程序,但我写的最后一个应用程序是一个文件中的所有控件的真正混乱。
我在这里忽略了一些明显的东西吗?
任何帮助将非常感激。
解决方案
首先,您的方法完全可以。
您看到的错误实际上与Java无关——它是Scala编译器的输出!它只是说,当它期待另一种类型的元素(在这种情况下是一个实例)时,它已经提供了一种类型的元素(在这种情况下,一个接受 ascalafx.event.ActionEvent
并返回的函数)。Unit
javafx.event.EventHandler[javafx.event.ActionEvent]
ScalaFX只是JavaFX库的一组对Scala友好的包装器;如果没有在两组元素之间转换的转换函数,Scala编译器会在需要JavaFX元素时抱怨找不到ScalaFX元素,反之亦然。implicit
解决方案是确保将以下import
内容添加到您的每个ScalaFX源文件中:
import scalafx.Includes._
(您在主源文件的顶部有这个,但不是其他的。)
这将确保您的ScalaFX ActionEvent
处理程序转换为JavaFX等价物,从而使您的生活更轻松一些。
这是ScalaFX的一种非常常见的错误类型,几乎总是可以通过指定上述内容来解决import
。(如果这import
不能解决您的问题,那么您通常会遇到真正的类型混淆情况,在这种情况下您只是使用了错误类型的对象。)
所以,这就是我认为您的代码需要的样子:
Main.scala
:
import scalafx.Includes._
import scalafx.application.JFXApp
import scalafx.scene.Scene
import buttonsandlabel._
object Main extends JFXApp {
stage = new JFXApp.PrimaryStage {
title = "Test-Program"
scene = new Scene(300, 200) {
content = List(Labels.label, Buttons.button1, Buttons.button2)
}
}
}
buttonsandlabel/Labels.scala
:
package buttonsandlabel
import scalafx.Includes._
import scalafx.scene.control.Label
object Labels {
val label = new Label("Nothing happened yet") {
layoutX = 20
layoutY = 20
}
}
buttonsandlabel/Buttons.scala
:
package buttonsandlabel
import scalafx.Includes._
import scalafx.scene.control.Button
import scalafx.event.ActionEvent
import Labels.label
object Buttons {
val button1 = new Button("Button 1") {
layoutX = 20
layoutY = 50
onAction = (e: ActionEvent) => {
label.text = "B1 klicked"
}
}
val button2 = new Button("Button 2") {
layoutX = 20
layoutY = 80
onAction = (e: ActionEvent) => {
label.text = "B2 klicked"
}
}
}
(请注意,按照惯例,包名称通常都是小写的。)
您需要注意的一件事是JavaFX 应用程序线程:与ScalaFX(或JavaFX )交互的所有代码都必须在此线程上执行。如果你从不同的线程访问ScalaFX / JavaFX,你会得到一个错误异常。(这确保了所有此类应用程序都是线程安全的。)如果您不熟悉多线程,请不要担心,ScalaFX 会以一种相当简单的方式初始化您的应用程序。通常,所需要的只是将初始化代码放入主应用程序对象的构造函数(扩展的对象JFXApp
)。
当您开始在其他类和对象中创建ScalaFX元素时,您需要格外小心。Anobject
在第一次被引用时被初始化。如果它首先被未在JavaFX 应用程序线程上执行的代码引用,那么您将获得线程错误异常。一种可能的选择是将此类代码放入def
orlazy val
成员中,以便仅在直接引用时执行它们。
或者,您可能必须通过调用您的代码scalafx.application.Platform.runLater()
。
有关JavaFX 应用程序线程的更多信息,请参阅JavaFX文档。
推荐阅读
- android - 如何检查我们是否在 Android 上拥有特定的文件 uri 权限?
- javascript - 等待给函数的回调的问题
- tensorflow - 通过 pickle 保存 RL 代理,由于 pickle.thread_RLock 无法保存 - 此错误的根源是什么?
- reactjs - Next.js 和 Gatsby.js 是否使用拆分代码可加载组件?
- oracle - 在插入到 oracle 表之前比较差异
- ffmpeg - 使用ffmpeg录制时从视频中提取帧
- r - 在定义之前如何使用 R 函数
- sql - 将 Varchar2 数据转换为数字
- azure - HTTP 错误 500.30 - ANCM 进程中启动失败 - 找不到登录匹配
- python - if/elif 条件在它应该在递归函数中时未触发