JavaFX
January 12, 2018

References

JavaFX

Periodic action

1
2
3
4
5
6
7
8
Timeline timeline = new Timeline(
        new KeyFrame(
                Duration.millis(2500),
                ae -> System.out.println("Periodic action")
        )
);
timeline.setCycleCount(Animation.INDEFINITE);
timeline.play();

FXML controller - constructor vs initialize method

The constructor is called first, then any @FXML annotated fields are populated, then initialize() is called. So the constructor does NOT have access to @FXML fields referring to components defined in the .fxml file, while initialize() does have access to them.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
public class MyController implements Initializable {
    @FXML
    TableView<MyModel> tableView;

    public MyController() {
        tableView.getItems().addAll(getDataFromSource()); // results in NullPointerException, as tableView is null at this point.
    }

    @FXML
    public void initialize(URL url, ResourceBundle rb) {
        tableView.getItems().addAll(getDataFromSource()); // Perfectly Ok here, as FXMLLoader already populated all @FXML annotated members.
    }
}

Scene UserAgentStylesheet

Caspian is the theme that shipped as default in JavaFX 2.x.

1
scene.setUserAgentStylesheet(STYLESHEET_CASPIAN);

Modena is the default theme for JavaFX 8.x.

1
scene.setUserAgentStylesheet(STYLESHEET_MODENA);

High Contrast Themes

High contrast themes can be set with a command line option

1
-Dcom.sun.javafx.highContrastTheme=yellowOnBlack

The valid values are yellowOnBlack, whiteOnBlack, or blackOnWhite.

Virtual keyboard

Virtual keyboard can be enabled with below command line options. You must add these flags to the java VM, not to the application.

1
2
3
-Dcom.sun.javafx.isEmbedded=true
-Dcom.sun.javafx.touch=true
-Dcom.sun.javafx.virtualKeyboard=javafx

To customize the keyboard layout check /com/sun/javafx/scene/control/skin/caspian/fxvk.css in ${JRE/JDK_INSTALL}/jre/lib/ext/jfxrt.jar for the css fields influencing the keyboard.

To run command line options in Netbeans IDE, put VM option inside nbaction.xml

1
<runfx.args>-jar -Dcom.sun.javafx.isEmbedded=true -Dcom.sun.javafx.touch=true -Dcom.sun.javafx.virtualKeyboard=javafx ${project.build.directory}/${project.build.finalName}.jar</runfx.args>

To have virtual keyboard for a textField use below code snippets. Use properties

1
2
TextField textField = new TextField();
textField.getProperties().put(FXVK.VK_TYPE_PROP_KEY, "numeric");

VK_TYPE_PROP_KEY can only get text, numeric, url, email values.

or use listener

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
textField.focusedProperty().addListener((ObservableValue<? extends Boolean> arg0, Boolean oldPropertyValue, Boolean newPropertyValue) -> {
    VirtualKeyboard keyboard = new VirtualKeyboard();
    if (newPropertyValue) {
        keyboard.show(textField);
    } else {
        keyboard.hide();
    }
});

public class VirtualKeyboard {
    public void show(TextField textField) {
        textField.getProperties().put(FXVK.VK_TYPE_PROP_KEY, "numeric");
        FXVK.init(textField);
        FXVK.attach(textField);
    }
    public void hide() {
        FXVK.detach();
    }
}

To prevent opening virtual keyboard

1
2
3
4
5
6
7
8
textField.focusedProperty().addListener(new ChangeListener<Boolean>()
{
    public void changed(ObservableValue<? extends Boolean> arg0, Boolean oldPropertyValue, Boolean newPropertyValue)
    {
        if (newPropertyValue)
            FXVK.detach();
    }
});

Display additional values in Pie Chart

Binding the pie chart data name

1
2
3
4
5
6
7
pieChartData.forEach(data ->
  data.nameProperty().bind(
    Bindings.concat(
      data.getName(), " ", data.pieValueProperty(), " Tons"
    )
  )
);

If you want to avoid recomputing the total every time there’s a mouse event, you can create a DoubleBinding to store it:

1
DoubleBinding total = Bindings.createDoubleBinding(() -> pieChartData.stream().collect(Collectors.summingDouble(PieChart.Data::getPieValue)), pieChartData);

If you have changing values and/or want to avoid displaying the values in the chart legend, you could modify the text label instead of changing the data names.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
chart = new PieChart(pieChartData) {
  @Override
  protected void layoutChartChildren(double top, double left, double contentWidth, double contentHeight) {
    if (getLabelsVisible()) {
      getData().forEach(d -> {
        Optional<Node> opTextNode = chart.lookupAll(".chart-pie-label").stream().filter(n -> n instanceof Text && ((Text) n).getText().contains(d.getName())).findAny();
        if (opTextNode.isPresent()) {
          ((Text) opTextNode.get()).setText(d.getName() + " " + d.getPieValue() + " Tons");
        }
      });
    }
    super.layoutChartChildren(top, left, contentWidth, contentHeight);
  }
};