我正在尝试使用以下代码从http://www.scalafx.org启动ScalaFX Hello World应用程序:

package car.cadr

object ApplicationStarter {
    def main(args: Array[String]) =
        javafx.application.Application.launch(classOf[HelloStageDemo], args: _*)
}

为了澄清,我在car.cadr包中有两个Scala文件:ApplicationStarter.scalaHelloStageDemo.scalaHelloStageDemo.scala启动并运行得非常好,但是编译器抱怨not found: type HelloStageDemo上的ApplicationStarter.scala。即使我使用import car.cadr.HelloStageDemo手动导入它,编译器仍然会抱怨。

我正在使用Scala 2.11.1和ScalaFx 8.0.20-R6。

最佳答案

您在这里遇到几个问题。

让我们从编译器告诉您的内容开始:not found: type HelloStageDemo。这是有道理的,因为HelloStageDemo示例定义了一个object而不是一个类:因此,scalac编译器实际上输出了一个名为HelloStageDemo$的类(因为您还可以定义一个class HelloStageDemo,并且都需要使用不同的名称进行编译)。

接下来,如果将object HelloStageDemo更改为class HelloStageDemo,则会出现以下错误:

Error:(7, 36) overloaded method value launch with alternatives:
  (x$1: String*)Unit <and>
  (x$1: Class[_ <: javafx.application.Application],x$2: String*)Unit
 cannot be applied to (Class[car.cadr.HelloStageDemo], String)

这是因为launch方法仅存在以下签名(此处为Java):
  • public static void launch(Class<? extends javafx.application.Application> appClass, String... args)
  • public static void launch(String... args)

  • 但是HelloStageDemo既不是String也不是javafx.application.Application的一种,因此这不起作用。

    这是因为ScalaFX的JFXApp特性的工作方式。这是您以通常方式启动ScalaFX应用程序时执行的主要方法(即,主要类是扩展的JFXApp):
    import javafx.{application => jfxa}
    
    trait JFXApp extends DelayedInit {
      // ...code removed for clarity...
      def main(args: Array[String]) {
        JFXApp.ACTIVE_APP = this
        arguments = args
        // Put any further non-essential initialization here.
        /* Launch the JFX application.
        */
        jfxa.Application.launch(classOf[AppHelper], args: _*)
      }
      // ...code removed for clarity...
    }
    

    因此,在ScalaFX中,扩展javafx.application.Application的类不是您实现的类,而是ScalaFX提供的AppHelper类。注意,main方法首先在ACTIVE_APP的伴随对象上设置JFXApp属性:实际上,AppHelper将要做的是start JFXApp.ACTIVE_APP。这是代码:
    package scalafx.application
    
    private[application] class AppHelper extends javafx.application.Application {
      def start(stage: javafx.stage.Stage) {
        JFXApp.STAGE = stage
        JFXApp.ACTIVE_APP.init()
        if (JFXApp.AUTO_SHOW) {
          JFXApp.STAGE.show()
        }
      }
    
      override def stop() {
        JFXApp.ACTIVE_APP.stopApp()
      }
    }
    

    总之,如果您要启动HelloStageDemo,但由于某种原因,您不希望HelloStageDemo成为主类,则最简单的解决方案是仅调用main方法-毕竟,它只是一种与其他方法相同的方法:
    package car.cadr
    
    object ApplicationStarter {
      def main(args: Array[String]) =
        HelloStageDemo.main(Array())
    }
    

    但是,如果由于某种原因,您绝对必须通过javafx.application.Application.launch方法启动ScalaFX应用程序,那么我认为最好的解决方案是根据自己的喜好重新实现AppHelper类,这看起来应该非常简单。

    10-06 08:41