controls - ScalaFX:是否可以在应用程序对象以外的对象中定义控件?

标签 controls scalafx

我想要完成的是:拥有一个 ScalaFX 应用程序,其中包含一些有序的 对象,称为 ButtonsLabelsCheckboxes 等等,以保持一切井井有条。

这里有一个小例子来说明我的意思:

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)
    }
  }
}

此代码显示了一个带有标签和两个按钮的窗口,按钮更改标签的文本。

这很好。

但是当我的代码随着更多控件的增长而增长时,事情就会变得一团糟。

这就是为什么我试图将控件转移到其他对象(在不同的文件中)。我已将标签放入一个名为 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 编译器输出的!它只是说它已经提供了一种类型的元素(在本例中,一个函数接受 scalafx.event.ActionEvent 并返回 Unit)期待另一种类型的元素(在本例中为 javafx.event.EventHandler[javafx.event.ActionEvent] 实例)。

ScalaFX 只是一组 Scala 友好的 JavaFX 包装器;如果没有在两组元素之间进行转换的隐式 转换函数,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)交互的所有代码em>) 必须在此线程上执行。如果您从不同的线程访问 ScalaFX/JavaFX,您将收到错误异常。 (这确保所有此类应用程序都是线程安全的。)如果您不熟悉多线程,请不要担心,ScalaFX 以这种方式初始化您的应用程序这是相当微不足道的。通常,所需要做的就是将初始化代码放入主应用程序对象的构造函数(扩展 JFXApp 的对象)。

当您开始在其他类和对象中创建 ScalaFX 元素时,您需要格外小心。 object 在第一次被引用时被初始化。如果它首先被JavaFX 应用程序线程 上执行的代码引用,那么您将得到线程错误异常。一种可能的选择是将此类代码放入 deflazy val 成员中,以便它们仅在直接引用时执行。

或者,您可能必须通过 scalafx.application.Platform.runLater() 调用您的代码。

有关 JavaFX 应用程序线程的更多信息,请参阅 JavaFX documentation .

关于controls - ScalaFX:是否可以在应用程序对象以外的对象中定义控件?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/52446778/

相关文章:

python - 用于单圈时间优化的 Gekko(python)

具有许多用户控件的 WPF 应用程序

javascript - 当 mp4 是唯一来源时,自定义 HTML5 视频控件不起作用

java - 如何限制 ScrollPane 内容的宽度

scala - 如何将ScalaFXML与Gradle相结合?

python - Tkinter 看透窗口不受鼠标点击影响

c# - 向 Microsoft WinForm 控件添加元素

ScalaFX - 如何使用方法获取场景的标题

scala - 如何让 ScalaFX 在 SBT 控制台中发挥​​出色?

java - 使 ScalaFx 在 JDK 8 和 11 上都能工作