javascalajavafxsbtscalafx

SBT won't compile HelloWorld ScalaFX example, complains about javafx missing from the classpath


I am new to Scala, and have never used a build tool before, and I am having some trouble getting the HelloWorld example on the scalafx quickstart page to compile.

I previously tried to use the scala IDE 4.7.0 Release to run the code, by creating a new scala project, and adding the scalafx.jar version 8.0.102-R11 as an external jar in the build path libraries' option. However, when I right clicked on the project and selected "Run as", there was no option to run it as a Scala Application, and trying to use the object name in a new run configuration didn't seem to work. I decided to try using the command line with SBT instead.

I am running Windows 10, and I have Java 8 installed, as well as JDK 12.0.2. I have created a project in my downloads folder, inside a folder called scalahelloworld, and ran the following command:

sbt new scala/hello-world.g8

This created the hello world project normally, and it compiles and runs without issues. However, when I tried following the instructions on the quick start guide for scalafx, adding the line

libraryDependencies += "org.scalafx" %% "scalafx" % "8.0.144-R12"

to build.sbt, and well as using their example code in my main object, it gives me some compiling errors:

C:\Users\hugo.barroca\Downloads\SBT Project\scalahelloworld>sbt
Java HotSpot(TM) 64-Bit Server VM warning: Ignoring option MaxPermSize; support was removed in 8.0
Java HotSpot(TM) 64-Bit Server VM warning: Ignoring option MaxPermSize; support was removed in 8.0
[info] Loading project definition from C:\Users\hugo.barroca\Downloads\SBT Project\scalahelloworld\project
[info] Loading settings for project scalahelloworld from build.sbt ...
[info] Set current project to hello-world (in build file:/C:/Users/hugo.barroca/Downloads/SBT%20Project/scalahelloworld/)
[info] sbt server started at local:sbt-server-3c8f646db648b9d2b646
sbt:hello-world> compile
[info] Compiling 1 Scala source to C:\Users\hugo.barroca\Downloads\SBT Project\scalahelloworld\target\scala-2.12\classes ...
[error] C:\Users\hugo.barroca\Downloads\SBT Project\scalahelloworld\src\main\scala\Main.scala:15:3: Symbol 'type javafx.event.EventTarget' is missing from the classpath.
[error] This symbol is required by 'class scalafx.stage.Window'.
[error] Make sure that type EventTarget is in your classpath and check for conflicting dependencies with `-Ylog-classpath`.
[error] A full rebuild may help if 'Window.class' was compiled against an incompatible version of javafx.event.
[error]   stage = new PrimaryStage {
[error]   ^
[error] C:\Users\hugo.barroca\Downloads\SBT Project\scalahelloworld\src\main\scala\Main.scala:17:17: Symbol 'term javafx.css' is missing from the classpath.
[error] This symbol is required by 'trait scalafx.css.Styleable'.
[error] Make sure that term css is in your classpath and check for conflicting dependencies with `-Ylog-classpath`.
[error] A full rebuild may help if 'Styleable.class' was compiled against an incompatible version of javafx.
[error]     scene = new Scene {
[error]                 ^
[error] C:\Users\hugo.barroca\Downloads\SBT Project\scalahelloworld\src\main\scala\Main.scala:17:5: Symbol 'type javafx.scene.Scene' is missing from the classpath.
[error] This symbol is required by 'class scalafx.scene.Scene'.
[error] Make sure that type Scene is in your classpath and check for conflicting dependencies with `-Ylog-classpath`.
[error] A full rebuild may help if 'Scene.class' was compiled against an incompatible version of javafx.scene.
[error]     scene = new Scene {
[error]     ^
[error] C:\Users\hugo.barroca\Downloads\SBT Project\scalahelloworld\src\main\scala\Main.scala:22:15: Symbol 'type javafx.scene.text.Text' is missing from the classpath.
[error] This symbol is required by 'class scalafx.scene.text.Text'.
[error] Make sure that type Text is in your classpath and check for conflicting dependencies with `-Ylog-classpath`.
[error] A full rebuild may help if 'Text.class' was compiled against an incompatible version of javafx.scene.text.
[error]           new Text {
[error]               ^
[error] C:\Users\hugo.barroca\Downloads\SBT Project\scalahelloworld\src\main\scala\Main.scala:25:24: Symbol 'term javafx.scene.paint' is missing from the classpath.
[error] This symbol is required by 'class scalafx.scene.paint.LinearGradient'.
[error] Make sure that term paint is in your classpath and check for conflicting dependencies with `-Ylog-classpath`.
[error] A full rebuild may help if 'LinearGradient.class' was compiled against an incompatible version of javafx.scene.
[error]             fill = new LinearGradient(
[error]                        ^
[error] C:\Users\hugo.barroca\Downloads\SBT Project\scalahelloworld\src\main\scala\Main.scala:36:26: Symbol 'type javafx.scene.effect.DropShadow' is missing from the classpath.
[error] This symbol is required by 'class scalafx.scene.effect.DropShadow'.
[error] Make sure that type DropShadow is in your classpath and check for conflicting dependencies with `-Ylog-classpath`.
[error] A full rebuild may help if 'DropShadow.class' was compiled against an incompatible version of javafx.scene.effect.
[error]             effect = new DropShadow {
[error]                          ^
[error] 6 errors found
[error] (Compile / compileIncremental) Compilation failed
sbt:hello-world[error] Total time: 4 s, completed 23/08/2019, 13:19:55
>
sbt:hello-world>

I have come across some SO pages which led me to believe the problem might be either with my version of Java or JDK, or with the classpath. However, I haven't been able to solve it so far. I have tried reinstalling Java, the JDK, STB and tried different versions of the ScalaFX jar, in particular version 8.0.12. I have also tried installing openjfx following this post. So far there's been no changes.

The only code I have is that of the example file:

package hello

import scalafx.application.JFXApp
import scalafx.application.JFXApp.PrimaryStage
import scalafx.geometry.Insets
import scalafx.scene.Scene
import scalafx.scene.effect.DropShadow
import scalafx.scene.layout.HBox
import scalafx.scene.paint.Color._
import scalafx.scene.paint.{Stops, LinearGradient}
import scalafx.scene.text.Text

object Main extends JFXApp {

  stage = new PrimaryStage {
    title = "ScalaFX Hello World"
    scene = new Scene {
      fill = Black
      content = new HBox {
        padding = Insets(20)
        children = Seq(
          new Text {
            text = "Hello "
            style = "-fx-font-size: 48pt"
            fill = new LinearGradient(
              endX = 0,
              stops = Stops(PaleGreen, SeaGreen))
          },
          new Text {
            text = "World!!!"
            style = "-fx-font-size: 48pt"
            fill = new LinearGradient(
              endX = 0,
              stops = Stops(Cyan, DodgerBlue)
            )
            effect = new DropShadow {
              color = DodgerBlue
              radius = 25
              spread = 0.25
            }
          }
        )
      }
    }
  }
}

How would I go about solving this particular issue, so that the code compiles properly and displays the HelloWorld scalafx window?


Solution

  • A bit of digging shows that you most likely need to add a OS-specific dependency for the JavaFX binaries. Add the following to the bottom of your build.sbt

    lazy val osName = System.getProperty("os.name") match {
      case n if n.startsWith("Linux") => "linux"
      case n if n.startsWith("Mac") => "mac"
      case n if n.startsWith("Windows") => "win"
      case _ => throw new Exception("Unknown platform!")
    }
    
    // Add JavaFX dependencies
    lazy val javaFXModules = Seq("base", "controls", "fxml", "graphics", "media", "swing", "web")
    libraryDependencies ++= javaFXModules.map( m=>
      "org.openjfx" % s"javafx-$m" % "11" classifier osName
    )
    

    As they do in the example project: https://github.com/scalafx/scalafx-hello-world/blob/master/build.sbt

    It can also be an issue with some of the JDK distrubutions, such as the OpenJDK distribution on Ubuntu. If I recall right there are two different ways to solve it. One is to add JavaFX to your dependencies:

    libraryDependencies += "org.openjfx" % "javafx" % "12.0.2" pomOnly()
    

    If I remember right this is probably the nicest way to do it. Should that work add it through your package manager, in Ubuntu that would be:

    sudo apt install openjdk-8-jdk openjfx
    

    https://mvnrepository.com/artifact/org.openjfx/javafx and https://askubuntu.com/questions/1091157/javafx-missing-ubuntu-18-04 might be useful.

    Also as the askubuntu points out, you probably want to make sure you set it to run using Java 8 for your projects.