ClojureFX Manual
ClojureFX Manual

ClojureFX Manual

Table of Contents

ClojureFX

This is the documentation to ClojureFX, version 0.4.0.


Next: , Previous: , Up: Top   [Contents][Index]

1 Installation and deployment

The first, straightforward part of this is to add the dependency to your project.clj or build.boot, which consists simply of adding [clojurefx "0.4.0"].

For the users of OpenJDK 7 and 8, OpenJFX, the opensource implementation of JavaFX, is not included yet (it will be starting with OpenJDK 9). Luckily, many Linux distributions ship a separate OpenJFX package by now, but for those that don’t, the OpenJDK wiki has an article “Building OpenJFX”. Alternatively, you can of course install the Oracle JDK manually.


2 Getting started

(require '[clojurefx.clojurefx :as fx])

To get the JavaFX environment up and running, you can’t just initialize some classes and fire up a window, as is the case with Swing; you first have to initialise the environment. For this, you have two choices: either use a “nasty hack” Oracle themselves show, or go down the Java road and subclass ‘javafx.application.Application’.

For the “nasty hack”, you have to add a defonce before you import JavaFX classes (so, best suited for a core.clj ns). You can then manually create a Stage and add a Scene to it.

(defonce force-toolkit-init (javafx.embed.swing.JFXPanel.))

Subclassing ‘javafx.application.Application’ is a tad more work and requires you to aot-compile the namespace:

(ns example.core
  (:require [clojurefx.clojurefx :as fx])
  (:gen-class :main true
              :extends javafx.application.Application))

(defn -init [this]
  nil)

(defn -start [this ^javafx.stage.Stage stage]
  (.show stage))

(defn -stop [this]
  nil)

(defn -main [& args]
    (javafx.application.Application/launch example.core args))

2.1 Core API

clojurefx.clojurefx: run-now code

This macro runs the code given on the JavaFX thread and blocks the current thread until the execution has finished.

clojurefx.clojurefx: run-later code

This macro runs the code given on the JavaFX thread and immediately returns. Prefixing the s-exp with an @ has the same effect as using run-now.


Next: , Previous: , Up: Top   [Contents][Index]

3 Coding a scenegraph

This part of the library has not been tested for a long time; I will get to it eventually, but expect things to be somewhat broken.

(require '[clojurefx.clojure :refer [compile]])
(compile [VBox {:id "TopLevelVBox"
                :children [Label {:text "Hi!"}
                           Label {:text "I'm ClojureFX!"}
                           HBox {:id "HorizontalBox"
                                 :children [Button {:text "Alright."}]}]}])

3.1 API

clojurefx.clojurefx: compile code

Turns the Hiccup-like tree into a JavaFX-Node.


Next: , Previous: , Up: Top   [Contents][Index]

4 FXML and controllers

(require '[clojurefx.fxml :as fxml])

FXML is an XML format describing a JavaFX user interface. It also allows defining action handlers and, similar to HTML, inline scripting via script tags. You can find an introduction on this site.

ClojureFX provides an idiomatic interface to load FXML files, and in this new version can even generate a controller class for you at runtime.


4.1 Loading FXML files

So you created an FXML file, probably with the SceneBuilder, and obviously now want to use it in your application. Doing so looks tedious in the JavaFX docs, but it is actually straightforward. All you need is some place to add the loaded Node - this could be the Scene object, or simply any JavaFX Parent element. The loader function returns a pure javafx.scene.Node-based object.

(require '[clojurefx.fxml :as fxml])
(def mainwindow (fxml/load-fxml "resources/fxml/mainwindow.fxml"))
     ;; => javafx.scene.Node
(.setContent my-scroll-pane mainwindow)

You’re already good to go!


4.2 Generating controller classes

When creating an FXML file, you have built-in features to bind properties and call functions in an associated controller class. Before actually writing any Clojure, let’s see how you can prepare your FXML file to get the most out of it.

First, at your outermost element in the file, you have to tell it the class name of its JVM sibling it is going to call. For that, open it, and add the fx:controller attribute: fx:controller="ch.lyrion.MyController". It is not very important how you name the class, as long as it has a package and doesn’t exist anywhere else.

To bind any element to your new controller (in the form of a Property), you need the fx:id attribute. Let’s try it with that label: <Label fx:id="MyLabel" />. That way, you’ll always have access to it as long as you have the controller instance with you. Note that the CamelCase will be automatically converted to kebab-case when using the designated accessors from ClojureFX!

Next, you can define action handlers. Note that “Special Handlers” (as defined here) are not yet fully supported; I’m working on them! You simply provide the attribute, e.g. an onAction attribute, with the method name prefixed with a pound sign; note that the method name CamelCase will be automatically converted to kebab-case. E.g. <Button onAction="#buttonClicked" /> will call (button-clicked controller-instance event) in the namespace you provided (see below).

Now, finally, it is time to weld the parts together. But wait! Your FXML file doesn’t have any companion, no controller class, let alone the ch.lyrion.MyController we told it to look for! No worries, we got you covered. load-fxml-with-controller has your and your file’s back. It doesn’t just load the FXML and returns a Node, it also parses the source and generates your file’s companion on the fly. For that, it needs a couple more infos than load-fxml though: first, of course, the file path, but also the fully qualified clojure function in String form that will be called when the class gets initialized by JavaFX. Note that all action handlers defined above also have to be in the namespace of that function.


4.3 FXML scripting

Unfortunately, FXML scripting is currently broken (outdated JSR-223 implementation). Stay tuned!


4.4 API

clojurefx.fxml: load-fxml filename

With this command, ClojureFX loads an FXML file and returns it as a javafx.scene.Node. Note that the filename will be parsed by clojure.io/resource before loading.

clojurefx.fxml: generate-controller filename init-fn

Generates a controller using the fx:id definitions in the given filename.

clojurefx.fxml: load-fxml-with-controller filename init-fn

Like load-fxml, but also generates and loads an accompanying controller class using generate-controller.


Next: , Previous: , Up: Top   [Contents][Index]

5 Event handling

Coming soon.


Next: , Previous: , Up: Top   [Contents][Index]

6 Roadmap

  • Allow for non-ActionEvent binding.
  • Testing and fixing Scenegraph coding API.
  • Fixing JSR-223 implementation.

Previous: , Up: Top   [Contents][Index]

Index

Jump to:   C   G   L   R  
Index Entry  Section

C
compile: Scenegraph API

G
generate-controller: FXML API

L
load-fxml: FXML API
load-fxml-with-controller: FXML API

R
run-later: Core API
run-now: Core API

Jump to:   C   G   L   R