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.
source to share
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.
source to share
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.
source to share