ScalaFX:是否可以在应用程序对象以外的对象中定义控件?
ScalaFX: Is it possible to define controls in objects other than the application object?
我想要完成的是:拥有一个 ScalaFX 应用程序,其中包含一些名为 Buttons
、Labels
的有序 object
, 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)
}
}
}
此代码显示了一个带有标签和两个按钮的 window,按钮更改标签的文本。
效果很好。
但是当我的代码随着更多的控件而增长时,事情就变得混乱了。
这就是我尝试将控件转移到其他 object
的原因(在不同的文件中)。我已将标签放入一个名为 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 编译器输出的!它只是说,当它期待另一种类型的元素(一个 javafx.event.EventHandler[javafx.event.ActionEvent]
实例,在这种情况下)。
ScalaFX 只是一组 Scala 友好的包装器 JavaFX图书馆;如果没有在两组元素之间进行转换的 implicit
转换函数,Scala 编译器会在需要时抱怨找不到 ScalaFX 元素JavaFX 元素,反之亦然.
解决方案是确保将以下 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 元素时,您需要格外小心。 object
在第一次被引用时被初始化。如果它首先被 not 在 JavaFX Application Thread 上执行的代码引用,那么您将得到线程错误异常.一种可能的选择是将此类代码放入 def
或 lazy val
成员中,以便它们仅在直接引用时执行。
或者,您可能必须通过 scalafx.application.Platform.runLater()
调用您的代码。
有关 JavaFX 应用程序线程 的详细信息,请参阅 JavaFX documentation。
我想要完成的是:拥有一个 ScalaFX 应用程序,其中包含一些名为 Buttons
、Labels
的有序 object
, 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)
}
}
}
此代码显示了一个带有标签和两个按钮的 window,按钮更改标签的文本。
效果很好。
但是当我的代码随着更多的控件而增长时,事情就变得混乱了。
这就是我尝试将控件转移到其他 object
的原因(在不同的文件中)。我已将标签放入一个名为 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 编译器输出的!它只是说,当它期待另一种类型的元素(一个 javafx.event.EventHandler[javafx.event.ActionEvent]
实例,在这种情况下)。
ScalaFX 只是一组 Scala 友好的包装器 JavaFX图书馆;如果没有在两组元素之间进行转换的 implicit
转换函数,Scala 编译器会在需要时抱怨找不到 ScalaFX 元素JavaFX 元素,反之亦然.
解决方案是确保将以下 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 元素时,您需要格外小心。 object
在第一次被引用时被初始化。如果它首先被 not 在 JavaFX Application Thread 上执行的代码引用,那么您将得到线程错误异常.一种可能的选择是将此类代码放入 def
或 lazy val
成员中,以便它们仅在直接引用时执行。
或者,您可能必须通过 scalafx.application.Platform.runLater()
调用您的代码。
有关 JavaFX 应用程序线程 的详细信息,请参阅 JavaFX documentation。