开始使用Scala + JavaFX桌面应用程序开发

18

有没有关于构建Scala + JavaFX桌面应用程序的指南或教程?

我很难找到一个好的资源,我使用IntelliJ IDEA作为IDE。

即使是最简单的桌面“hello world”样例也会帮助很多,因为我不知道从哪里开始。

更新:这是我现在拥有的内容:

import javafx.application.Application
import javafx.scene.Scene
import javafx.scene.layout.StackPane
import javafx.stage.Stage
import javafx.scene.control.Label

class Test extends Application {
  override def start(primaryStage: Stage) {
    primaryStage.setTitle("Sup!")

    val root = new StackPane
    root.getChildren.add(new Label("Hello world!"))

    primaryStage.setScene(new Scene(root, 300, 300))
    primaryStage.show()
  }
}

object Test {
  def main(args: Array[String]) {
    val t = new Test
    t.start(new Stage)
  }
}

运行时我得到了以下结果:

异常:线程 "main" 抛出 java.lang.IllegalStateException 异常:不在 FX 应用程序线程上;当前线程 = main

如何使它能够显示带有标签的 hello world 窗口?


你之前使用Java编写过JavaFX吗?你用的是哪个IDE? - Luigi Plinge
@LuigiPlinge 我刚刚发现了JavaFX,大约一个月前我开始学习Scala。我正在使用IntelliJ IDE。 - Tower
1
我建议您可以先参考Oracle网站上的示例。http://www.oracle.com/technetwork/java/javafx/documentation/index.html 确保您能够使用Java运行示例,然后可以尝试将示例翻译成Scala。您可能还会对ScalaFX感兴趣,这是一个正在进行中的项目,旨在为该库生成惯用的Scala绑定。http://code.google.com/p/scalafx/ - Luigi Plinge
@LuigiPlinge 我已经更新了我的问题并附上了代码。你有任何想法如何从我停下来的地方继续吗? - Tower
3个回答

34

写Scala基于JavaFX应用程序时需要了解一些事情。

首先,这是一个样例Hello World应用程序:

import javafx.application.Application
import javafx.scene.Scene
import javafx.scene.layout.StackPane
import javafx.stage.Stage
import javafx.scene.control.Label

class Test extends Application {
  println("Test()")

  override def start(primaryStage: Stage) {
    primaryStage.setTitle("Sup!")

    val root = new StackPane
    root.getChildren.add(new Label("Hello world!"))

    primaryStage.setScene(new Scene(root, 300, 300))
    primaryStage.show()
  }
}

object Test {
  def main(args: Array[String]) {
    Application.launch(classOf[Test], args: _*)
  }
}

运行后您应该会得到如下内容:

图片描述

这是Java的官方Hello World示例:http://docs.oracle.com/javafx/2/get_started/hello_world.htm

主要的区别是:

  • 你需要编写所谓的伴生对象(companion object)并且包含def main()以启动实际的应用程序。
  • 你需要指定它将在Test类的上下文中运行,而不是在伴生对象中: Application.launch(classOf[Test], args: _*)

如果您直接使用Application.launch(args : _*) 试图运行应用程序,则会出现以下错误:

Exception in thread "main" java.lang.RuntimeException: Error: class Test$ is not a subclass of javafx.application.Application

如果想了解更多关于JavaFX的信息,请阅读官方文档:http://docs.oracle.com/javafx/index.html


1
你可以使用这种方式。
 class BuildFx extends Application{

  override def start(primaryStage: Stage): Unit = {
    primaryStage.setTitle("Scala")
    var btn=new Button("Say Hello Scala")
    val root=new StackPane()
    root.getChildren().add(btn)
    primaryStage.setScene(new Scene(root, 300, 300))
    primaryStage.show()

  }



  def launchIt():Unit={
    Application.launch()
  }

}

///////////////////////////////////////////////////////////
object Init{


  def main(args: Array[String]): Unit = {
    val buildFx=new BuildFx
    buildFx.launchIt()

  }
}

0

我能够在scala_swing中更加令人满意地解决这个问题,因为你可以使用参数实例化一个实例,然后稍后调用main来启动Swing。

这种解决方案允许在FX应用程序中获取参数,但代价是使用静态变量和可能存在其他问题。其中之一肯定不是多线程安全的。

package hack

/**
  * Created by WorkDay on 8/11/16.<br>
  * <br>
  * HelloTest shows a method which allows parameters to be passed
  * into your javaFX application as it is started
  * this allows it to be connected to non-FX code that existed before it.
  *
  * You could also pass a reference to the Application back
  * into the non-FX code if needed.
  */

import javafx.application.Application
import javafx.scene.Scene
import javafx.scene.layout.StackPane
import javafx.stage.Stage
import javafx.scene.control.Label

case class Data(data: String)

object SomeOtherCode extends App {
  HelloTest.launch(Data("brave"), Data("new"))
}

object HelloTest {
  var data1: Data = _
  var data2: Data = _
  def launch(data1: Data, data2: Data) = {
    HelloTest.data1 = data1
    HelloTest.data2 = data2
    Application.launch(classOf[HelloTest])
  }
}

private class HelloTest extends Application {
  val data1: Data = HelloTest.data1
  val data2: Data = HelloTest.data2


  override def start(primaryStage: Stage) {
    primaryStage.setTitle("Sup!")

    val root = new StackPane
    root.getChildren.add(new Label(s"Hello ${data1.data} ${data2.data} world!"))

    primaryStage.setScene(new Scene(root, 300, 300))
    primaryStage.setX(0)
    primaryStage.setY(0)
    primaryStage.show()
  }
}

[SO] 不是一个论坛,因此答案不能包含问题。如果您有问题,请开启一个新的问题,并将答案作为独立的答案留下。 - Brian Tompsett - 汤莱恩

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接