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

时间:2018-09-21 15:19:44

标签: controls scalafx

我要完成的工作是:拥有一个 ScalaFX 应用程序,其中包含一些名为Option Explicit Private Sub Test_It() Dim om_Item As Outlook.MailItem Dim oi_Inspector As Outlook.Inspector Dim wd_Doc As Word.Document Dim wd_Selection As Word.Selection Dim wr_Range As Word.Range Dim b_return As Boolean Dim str_Text As String str_Text = "Hello World" 'Zugriff auf aktive E-Mail Set oi_Inspector = Application.ActiveInspector() Set om_Item = oi_Inspector.CurrentItem Set wd_Doc = oi_Inspector.WordEditor 'Zugriff auf Textmarkierung in E-Mail Set wd_Selection = wd_Doc.Application.Selection wd_Selection.InsertBefore str_Text 'Zugriff auf 'virtuelle' Markierung 'wr_Range muss auf das ganze Dokument gesetzt werden ! Set wr_Range = wd_Doc.Content 'Suche in E-Mail Text With wr_Range.Find .Forward = True .ClearFormatting .MatchWholeWord = True .MatchCase = False .Wrap = wdFindStop .MatchWildcards = True .Text = "#%*%#" End With b_return = True Do While b_return b_return = wr_Range.Find.Execute If b_return Then ' Es wurde gefunden str_Text = wr_Range.Text 'schneide den Anfangstext und das Ende ab 'str_TextID = Mid$(str_TextID, 11, Len(str_TextID) - 12) MsgBox ("Es wurde noch folgender Schlüssel gefunden:" & vbCrLf & str_Text) End If Loop 'aktiv Range ändern 'wr_Range muss auf das ganze Dokument gesetzt werden ! Set wr_Range = wd_Doc.Content wr_Range.Start = wr_Range.Start + 20 wr_Range.End = wr_Range.End - 20 'Text formatieren With wr_Range.Font .ColorIndex = wdBlue .Bold = True .Italic = True .Underline = wdUnderlineDotDashHeavy End With 'Freigeben der verwendeten Variablen Set oi_Inspector = Nothing Set om_Item = Nothing Set wd_Doc = Nothing Set wd_Selection = Nothing Set wr_Range = Nothing End Sub objectButtons的漂亮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的对象中:

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

现在我被困住了,因为我不知道任何 Java

有人知道我是否有可能做我想做的事?

到目前为止,我尚未在网上找到任何有关此的信息。问题并没有阻止我编写所需的程序,但是我编写的最后一个应用程序确实把所有控件都放在一个文件中。

我在这里俯瞰明显的东西吗?

任何帮助将不胜感激。

1 个答案:

答案 0 :(得分:1)

首先,您的方法完全可以。

您看到的错误实际上与 Java 没有关系-它是 Scala 编译器输出的!它的全部意思是,当它期望另一种元素({{1时),已经为它提供了一种元素(在这种情况下,该函数接受scalafx.event.ActionEvent并返回Unit) }}实例)。

ScalaFX 只是用于 JavaFX 库的一组 Scala 友好包装器;如果没有javafx.event.EventHandler[javafx.event.ActionEvent]转换函数在两组元素之间进行转换, Scala 编译器将抱怨在需要 JavaFX 时找到 ScalaFX 元素。 em>元素,反之亦然。

解决方案是确保将以下implicit添加到每个 ScalaFX 源文件中:

import

(您在主源文件的顶部,但没有在其他文件的顶部。)

这将确保将您的 ScalaFX import scalafx.Includes._ 处理程序转换为等效的 JavaFX ,从而使您的生活更加轻松。

这是 ScalaFX 的一种非常常见的错误类型,几乎总是通过指定以上ActionEvent来解决。 (如果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

(请注意,按照惯例,程序包名称通常都是小写。)

您需要了解的一件事是 JavaFX应用程序线程:与 ScalaFX (或 JavaFX )必须在此线程上执行。如果您从其他线程访问 ScalaFX / JavaFX ,则会收到错误异常。 (这可确保所有此类应用程序都是 thread-safe 。)如果您不熟悉多线程,请不必担心, ScalaFX 会以这种方式初始化应用程序这是相当琐碎的。通常,所需要做的只是将初始化代码放入主应用程序对象的构造函数(扩展了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" } } } 的对象)中。

开始在其他类和对象中创建 ScalaFX 元素时,需要格外小心。 JFXApp在首次引用时被初始化。如果首先由在 JavaFX Application Thread 上执行的 not 代码首先引用,那么您将获得线程错误异常。一种可能的选择是将此类代码放入objectdef成员中,以便仅在直接引用时才执行。

或者,您可能必须通过lazy val来调用代码。

有关 JavaFX Application Thread 的更多信息,请参阅JavaFX documentation