Во-первых, ваш подход совершенно нормален.
Ошибка, которую вы видите, на самом деле не имеет ничего общего с Java - она выводится компилятором Scala !Все, что он говорит, это то, что ему был предоставлен один тип элемента (в данном случае, функция, которая принимает scalafx.event.ActionEvent
и возвращает Unit
), когда она ожидала другой тип элемента (экземпляр javafx.event.EventHandler[javafx.event.ActionEvent]
, в этомcase).
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
инициализируется при первой ссылке.Если на него сначала ссылается код, который не выполняется в потоке приложения JavaFX , то вы получите исключения ошибок потока.Один из возможных вариантов - поместить такой код в элементы def
или lazy val
, чтобы они выполнялись только при прямой ссылке.
В качестве альтернативы вам, возможно, придется вызывать код через scalafx.application.Platform.runLater()
.
Для получения дополнительной информации о потоке приложений JavaFX см. Документацию JavaFX .