DZone
Thanks for visiting DZone today,
Edit Profile
  • Manage Email Subscriptions
  • How to Post to DZone
  • Article Submission Guidelines
Sign Out View Profile
  • Post an Article
  • Manage My Drafts
Over 2 million developers have joined DZone.
Log In / Join
Refcards Trend Reports Events Over 2 million developers have joined DZone. Join Today! Thanks for visiting DZone today,
Edit Profile Manage Email Subscriptions Moderation Admin Console How to Post to DZone Article Submission Guidelines
View Profile
Sign Out
Refcards
Trend Reports
Events
Zones
Culture and Methodologies Agile Career Development Methodologies Team Management
Data Engineering AI/ML Big Data Data Databases IoT
Software Design and Architecture Cloud Architecture Containers Integration Microservices Performance Security
Coding Frameworks Java JavaScript Languages Tools
Testing, Deployment, and Maintenance Deployment DevOps and CI/CD Maintenance Monitoring and Observability Testing, Tools, and Frameworks
Culture and Methodologies
Agile Career Development Methodologies Team Management
Data Engineering
AI/ML Big Data Data Databases IoT
Software Design and Architecture
Cloud Architecture Containers Integration Microservices Performance Security
Coding
Frameworks Java JavaScript Languages Tools
Testing, Deployment, and Maintenance
Deployment DevOps and CI/CD Maintenance Monitoring and Observability Testing, Tools, and Frameworks
  1. DZone
  2. Data Engineering
  3. AI/ML
  4. Getting Started with ScalaFX and Resizable UIs

Getting Started with ScalaFX and Resizable UIs

Joachim Hofer user avatar by
Joachim Hofer
·
Jan. 08, 13 · Interview
Like (1)
Save
Tweet
Share
10.05K Views

Join the DZone community and get the full member experience.

Join For Free

When I was a school kid oh so long ago, the most permanent subject of my programming hobby was an AI for “Connect Four” (besides lots of genetic algorithm and neural network stuff, sigh). I remember very well the thousands of lines of code and the weeks I spent trying to get that right (using Turbo Pascal), and to get it to be able to beat me at the game. However, I got better at the game faster than my AI, I’m afraid.

Today I know that “Connect Four” is a solved problem. Still, I think it’s a nice programming playground. And as I wanted to find out how far I’ve come with my development skills since I was a school kid, I decided to ignore that research paper and use “Connect Four” as a playground for trying out Akka and ScalaFX for a bit over the holidays – if you want to skip ahead, you’ll find the results at Bitbucket.

So, here’s a blog about how I started out with ScalaFX in  that little project.

The first steps to getting started with ScalaFX were not immediately clear to me. There’s a tutorial about how to get started with ScalaFX within Eclipse alright, but for using it from SBT, I fortunately remembered a Herbstcampus talk by @phdoerfler. You can find the (German) slides and an SBT build file here. Turns out it’s quite easy.

The first thing you need to know about ScalaFX is that it’s unfortunately not published anywhere. That means that you have to publish it locally in order to be able to use it as a library.

Doing this means installing Mercurial if you haven’t got it already, and then cloning the ScalaFX repository:

hg clone https://code.google.com/p/scalafx/

Next, you have to package and publish ScalaFX. If you’ve got git installed, too, then this should do the trick:

sbt publish-local

However, if you don’t have git installed, you have to remove the project/plugins/project/PluginBuild.scala file first, which references an sbt plugin (used for the test target) cloned from git. This plugin is not really required for locally publishing ScalaFX, anyway.

Now you’re set for referencing ScalaFX in your own SBT build – just add ScalaFX as a library dependency, and also add the JavaFX runtime (coming from your local Java 7 installation, if it’s up-to-date as it should be) as a dependency:

libraryDependencies += "org.scalafx" % "scalafx" % "1.0-SNAPSHOT"

unmanagedJars in Compile += Attributed.blank(
    file(scala.util.Properties.javaHome) / "lib" / "jfxrt.jar")

fork in run := true

As you notice, I have also told the run command to fork in order to avoid “UnsatisfiedLinkError“s due to various classloader “magics”…

On to coding: For my Connect Four board, I wanted to start with a pane within a resizable window where I just do the layout myself, basically drawing the board with the help of ScalaFX shapes instead of using Graphics2D. At first I thought that that would be easy, but then I spend a lot of time on one single detail: Namely, how to get the ScalaFX UI to resize with the window. Incidentally, this is what spawned this blog post.

My main class started out quite simple, as any ScalaFX application does:

import scalafx.Includes._
import scalafx.application.JFXApp
import scalafx.stage.Stage

object Main extends JFXApp {
  stage = new Stage {
    title = "Akka Connect Four"
    width = 800
    height = 600
  }
}

This sets the stage, and that’s all. – Next, you have to add the scene graph to the stage. Normally, you’d do this by simply adding scene = new Scene { ... } to the stage. But that’s exactly what broke my neck when trying to make the scene resize together with the window. And the reason for this is that ScalaFX internally puts a JavaFX “group” as the root of the scene here, instead of a single component.

Using a single component as root for the ScalaFX scene graph unfortunately doesn’t seem to be well supported by ScalaFX. The only way I was able to make it work is by doing it like this, directly creating a scene via JavaFX:

import scalafx.Includes._
import scalafx.application.JFXApp
import scalafx.stage.Stage
import scalafx.scene.Scene
import scalafx.scene.layout.BorderPane

object Main extends JFXApp {
  stage = new Stage {
    title = "Akka Connect Four"
    width = 800
    height = 600

    scene = new Scene(new javafx.scene.Scene(root))
  }

  lazy val root = new BorderPane {}
}

I’m using a BorderPane here as a container so that I can arrange additional stuff around my Connect Four board later on.

Next, let’s add the basic board rectangle to the center of the root pane.

import scalafx.Includes._
import scalafx.application.JFXApp
import scalafx.stage.Stage
import scalafx.scene.Scene
import scalafx.scene.layout.{ Pane, BorderPane }
import scalafx.scene.shape.Rectangle
import javafx.scene.paint.{ Color => JFXColor }

object Main extends JFXApp {
  stage = new Stage {
    title = "Akka Connect Four"
    width = 800
    height = 600

    scene = new Scene(new javafx.scene.Scene(root))
  }

  lazy val root = new BorderPane {
    center = gamePane
  }

  lazy val gamePane: Pane = new Pane {
    content = showBoard(784.0, 562.0)
  }

  def showBoard(paneWidth: Double, paneHeight: Double) = {
    val offX = 50.0
    val offY = 50.0
    val boardWidth = paneWidth - offX * 2
    val boardHeight = paneHeight - offY * 2
    
    new Rectangle {
      x = offX
      y = offY
      width = boardWidth
      height = boardHeight
      fill = JFXColor.DEEPSKYBLUE
    }
  }
}

This way, we get a nice centered blue rectangle (I won’t add more details to it for the purpose of this blog post). However, you may have already noticed that the board still doesn’t resize itself when you resize the window. At least the pane itself does resize itself thanks to our trick with the root component above (you can check that by setting the background color, for example, or by using Scenic View – which is an awesome tool for debugging JavaFX UIs, by the way).

In order to get a resizing board, we still have to bind the width and height of the game pane to redrawing our board. Now, if there’s something that’s really awesome in ScalaFX, then it’s how simple this can be done, using “bind expressions”. In our case, we just want to show an updated board every time the width or height of the window changes. Therefore, we want to set width.onChange() and height.onChange().

Here’s what I did:

import scalafx.Includes._
import scalafx.application.JFXApp
import scalafx.stage.Stage
import scalafx.scene.Scene
import scalafx.scene.layout.{ Pane, BorderPane }
import scalafx.scene.shape.Rectangle
import javafx.scene.paint.{ Color => JFXColor }

object Main extends JFXApp {
  stage = new Stage {
    title = "Akka Connect Four"
    width = 800
    height = 600

    scene = new Scene(new javafx.scene.Scene(root))

    width onChange show
    height onChange show
  }

  lazy val root = new BorderPane {
    center = gamePane
  }

  lazy val gamePane: Pane = new Pane {
    content = showBoard(784.0, 562.0)
  }

  def show: Unit = {
    gamePane.content = showBoard(gamePane.width.get, gamePane.height.get)
  }


  def showBoard(paneWidth: Double, paneHeight: Double) = {
    val offX = 50.0
    val offY = 50.0
    val boardWidth = paneWidth - offX * 2
    val boardHeight = paneHeight - offY * 2
    
    new Rectangle {
      x = offX
      y = offY
      width = boardWidth
      height = boardHeight
      fill = JFXColor.DEEPSKYBLUE
    }
  }
}

And that’s it already: A resizable game board for my Connect Four UI.

And as I’m still a bloody ScalaFX newbie: Should you know a way to do any of the above easier, please write a comment below!

You can also check out the source code of the Connect Four application at BitBucket. – That said, it’s not complete in any way (no parallelism at all yet, no permanent brain, nearly completely unoptimized for performance, for example).

However, I got it to being able to play on par with me within a few days of eating christmas cookies and casually hacking, and that’s awesome and depressing at the same time! :)


IT neural network JavaFX Genetic algorithm application code style Blog Awesome (window manager) Git

Published at DZone with permission of Joachim Hofer, DZone MVB. See the original article here.

Opinions expressed by DZone contributors are their own.

Popular on DZone

  • RabbitMQ vs. Memphis.dev
  • Why Does DevOps Recommend Shift-Left Testing Principles?
  • PHP vs React
  • Writing a Modern HTTP(S) Tunnel in Rust

Comments

Partner Resources

X

ABOUT US

  • About DZone
  • Send feedback
  • Careers
  • Sitemap

ADVERTISE

  • Advertise with DZone

CONTRIBUTE ON DZONE

  • Article Submission Guidelines
  • Become a Contributor
  • Visit the Writers' Zone

LEGAL

  • Terms of Service
  • Privacy Policy

CONTACT US

  • 600 Park Offices Drive
  • Suite 300
  • Durham, NC 27709
  • support@dzone.com
  • +1 (919) 678-0300

Let's be friends: