Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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:

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. HelloStageDemo.scala starts and runs perfectly fine, but the compiler is complaining about not found: type HelloStageDemo on ApplicationStarter.scala. Even if I manually import it with import car.cadr.HelloStageDemo the compiler still complains.

I'm using Scala 2.11.1 and ScalaFx 8.0.20-R6.

like image 216
My other car is a cadr Avatar asked Dec 14 '25 03:12

My other car is a cadr


1 Answers

You have several problems here.

Let's start with the one the compiler is telling you about: 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).


Next, if you change your object HelloStageDemo for a class HelloStageDemo, you will 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 launch method exists only 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 is neither a String nor a kind of javafx.application.Application, so this cannot work.


This is because of the way ScalaFX's JFXApp trait works. 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):

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. 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. 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:

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.

like image 72
Cyäegha Avatar answered Dec 15 '25 21:12

Cyäegha