How do I run a ScalaFX application from Scala?

I am trying to run a ScalaFX Hello World application from http://www.scalafx.org with the following code:

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 package car.cadr

: ApplicationStarter.scala

and HelloStageDemo.scala

. HelloStageDemo.scala

starts and runs fine, but the compiler complains not found: type HelloStageDemo

on ApplicationStarter.scala

. Even if I manually import it with import car.cadr.HelloStageDemo

, the compiler still complains.

I am using Scala 2.11.1 and ScalaFx 8.0.20-R6.

+3


source to share


3 answers


You have several problems here.

To begin with, it tells you about someone compiler: not found: type HelloStageDemo

. This makes sense because the HelloStageDemo example defines object

, not a class: so the scalac compiler actually infers a class with a name HelloStageDemo$

(because you can define class HelloStageDemo

as well and both must be compiled with different names).




Then if you change your object HelloStageDemo

to class HelloStageDemo

, you get the following error:

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 method launch

only exists with the following signatures (here in Java):

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

  • public static void launch(String... args)

But HelloStageDemo

it is neither String

, nor kind javafx.application.Application

, so it won't work.




This has to do with how the ScalaFX property works JFXApp

. Here's the main metrhod that is run when the ScalaFX application starts up in the usual way (i.e. the main class is extensible 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 that extends javafx.application.Application

is not the one you implement, but the class AppHelper

provided by ScalaFX. Note that the main method first sets the property ACTIVE_APP

on the JFXApp

companion object: in practice, what AppHelper

will do is run 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 run HelloStageDemo

, but for some reason you don't want to HelloStageDemo

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:

package car.cadr

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

      

But if for some reason you absolutely need to start your ScalaFX application using a method javafx.application.Application.launch

, I think the best solution would be to re-link the class AppHelper

to your liking, which seems to be pretty simple.

+2


source


Here is a simple template for running ScalaFX applications.



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

class MyApp extends JFXApp {

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

      

0


source


Non ScalaFX solution:

I know this question was answered by the old one too. But if you want to use javafx.application.Application to run. Just give different names for class and object, resulting in no "MyClass $ .class" and "MyClass.class" where the second is not a child application but an object.

Solved my problem in a neat way.

0


source







All Articles