简体   繁体   English

如何从Scala中创建ScalaFX应用程序?

[英]How do Iaunch a ScalaFX application from Scala?

I'm trying to launch the ScalaFX Hello World application from http://www.scalafx.org with the following code: 我正在尝试使用以下代码从http://www.scalafx.org启动ScalaFX Hello World应用程序:

package car.cadr

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

To clarify, I have two Scala files in the car.cadr package: ApplicationStarter.scala and HelloStageDemo.scala . 为了澄清,我在car.cadr包中有两个Scala文件: ApplicationStarter.scalaHelloStageDemo.scala HelloStageDemo.scala starts and runs perfectly fine, but the compiler is complaining about not found: type HelloStageDemo on ApplicationStarter.scala . HelloStageDemo.scala启动并运行完全正常,但编译器抱怨not found: type HelloStageDemoApplicationStarter.scalanot found: type HelloStageDemo Even if I manually import it with import car.cadr.HelloStageDemo the compiler still complains. 即使我用import car.cadr.HelloStageDemo手动导入它,编译器仍然会抱怨。

I'm using Scala 2.11.1 and ScalaFx 8.0.20-R6. 我正在使用Scala 2.11.1和ScalaFx 8.0.20-R6。

You have several problems here. 你有几个问题。

Let's start with the one the compiler is telling you about: not found: type HelloStageDemo . 让我们从编译器告诉你的那个开始: not found: type HelloStageDemo This makes sense because the HelloStageDemo example defines an object and not a class: so the scalac compiler actually outputs a class named HelloStageDemo$ (because you could also define a class HelloStageDemo , and both need to be compiled with different names). 这是有道理的,因为HelloStageDemo示例定义了一个object而不是一个类:因此scalac编译器实际上输出了一个名为HelloStageDemo$的类(因为您还可以定义一个class HelloStageDemo ,并且两者都需要使用不同的名称进行编译)。


Next, if you change your object HelloStageDemo for a class HelloStageDemo , you will get the following error: 接下来,如果为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)

This is because the launch method exists only with the following signatures (here in Java): 这是因为launch方法仅存在以下签名(此处为Java):

  • public static void launch(Class<? extends javafx.application.Application> appClass, String... args)
  • public static void launch(String... args)

But HelloStageDemo is neither a String nor a kind of javafx.application.Application , so this cannot work. HelloStageDemo既不是String也不是javafx.application.Application ,所以这不行。


This is because of the way ScalaFX's JFXApp trait works. 这是因为ScalaFX的JFXApp特性的工作方式。 Here's the main metrhod that gets executed when you launch a ScalaFX application the usual way (ie., the main class is the one extending 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...
}

So, in ScalaFX, the class extending javafx.application.Application isn't the one you implement, but a AppHelper class provided by ScalaFX. 因此,在ScalaFX中,扩展javafx.application.Application的类不是您实现的类,而是AppHelper提供的AppHelper类。 Notice that the main method first sets the ACTIVE_APP property on JFXApp 's companion object: in practice, what AppHelper will do is start JFXApp.ACTIVE_APP . 请注意,main方法首先在JFXApp的伴随对象上设置ACTIVE_APP属性:实际上, AppHelper将执行的操作是启动JFXApp.ACTIVE_APP Here is the code: 这是代码:

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

In conclusion, if you want to launch HelloStageDemo but, for some reason, you don't want HelloStageDemo to be the main class, the simplest solution would be to just call the main method - after all, it's just a method like any other: 总之,如果你想启动HelloStageDemo但是由于某种原因,你不希望HelloStageDemo成为主类,最简单的解决方案就是调用main方法 - 毕竟,它只是一个像其他方法一样的方法:

package car.cadr

object ApplicationStarter {
  def main(args: Array[String]) =
    HelloStageDemo.main(Array())
}

But if, for some reason, you absolutely had to launch your ScalaFX application trough the javafx.application.Application.launch method, I think the best solution would be to re-implement the AppHelper class to your liking, which seems like it should be pretty simple. 但是,如果出于某种原因,您绝对必须通过javafx.application.Application.launch方法启动ScalaFX应用程序,我认为最好的解决方案是根据自己的喜好重新实现AppHelper类,这似乎应该是很简单。

Here is a simple template for launching ScalaFX applications. 这是一个用于启动ScalaFX应用程序的简单模板。

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

class MyApp extends JFXApp {

   override def start(primaryStage: Stage): Unit = {
      // initialization here
   } 
}

Non ScalaFX solution: 非ScalaFX解决方案:

I know this question is answered and old. 我知道这个问题已经回答了。 But if you want to use javafx.application.Application, to launch. 但是如果你想使用javafx.application.Application来启动。 Just set different names for the class and the object, with the result that there is no "MyClass$.class" and "MyClass.class" where the second one isn't the Applications Child but the object. 只需为类和对象设置不同的名称,结果是没有“MyClass $ .class”和“MyClass.class”,其中第二个不是Applications Child而是对象。

Solved my problem in a neat way. 以一种巧妙的方式解决了我的问题。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM