Shutting down Spring backed JavaFX application

This is just another short tip on how to combine JavaFX and the Spring Framework. These two technologies do not work perfectly together, but they can be made to cooperate. One of the two is the lead, meaning one is initialized first from the main method and therefore controls the lifecycle of the application. In my case this is the Spring framework as the user interface is optional. However I still want to handle the case where the user interface is closed (or the menu point quit is selected) and this should also shut down the application context of Spring.

There are three steps that should be taken:

  • Register the shutdown hooks for your application context. This has nothing to do with canceling the application in a controlled manner. This case covers things like Ctrl+C or kill -9.
((AbstractApplicationContext)context).registerShutdownHook();
  • Override the stop method of Application. When closing the application window, the stop method is called. You will want to hook into this method to signal the spring context that his end has come.
    @Override
    public void stop() throws Exception {
        System.out.println("Stopping the UI Application");

        stopUIApplicationContext();
        super.stop();
    }

In my case I used Guava’s EventBus to signal the context.

  • Finally in your code handling the context end it.
((AbstractApplicationContext)context).close();

That’s it, folks!

TextFlow with JavaFX 2

When ever you want to display a large portion of text in your application the Text node is your friend. Text allows you to define a wrapping width and thereby allows nice multyline text without letting you bother about the line break.

However what when your text is not that simple? It might contain portions that are differently formatted? Links? Or even icons?

JavaFX 8 has a solution for this: TextFlow. If you are however stuck with JavaFX 2 for whatever reason, there is simple workaround: pack all the Nodes into a FlowPane and define the wrapping width to be the preferred width.

public class DecoratedText extends FlowPane {

    private IntegerProperty wrappingWidth;
    private ReadOnlyObjectProperty<Font> font;
    public DecoratedText(Font font) {
        super(Orientation.HORIZONTAL);
        wrappingWidth = new SimpleIntegerProperty(this, "wrappingWidth", 0);
        getStylesheets().add(getClass().getResource(getClass().getSimpleName()+".css").toExternalForm());
        this.font = new SimpleObjectProperty<>(this, "font", font);
        prefWidthProperty().bindBidirectional(wrappingWidth);
    }

    /**
     * Append text. If the text represents a paragraph (indicated by '\n'), it
     * is not broken up into its parts.
     * @param text
     */
    public void append(String text) {
        if (text.endsWith("\n")) {
            Text decoText = new Text(text);
            //decoText.getStyleClass().add("decoratedText-text");
            decoText.setFont(font.get());
            decoText.wrappingWidthProperty().bind(wrappingWidth);
            getChildren().add(decoText);
        } else {
            String[] parts = text.split(" ");
            for (String part : parts) {
                Text decoText = new Text(part+" ");
                //decoText.getStyleClass().add("decoratedText-text");
                decoText.setFont(font.get());
                getChildren().add(decoText);
            }
        }
    }

    /**
     * Append a control.
     * @param control
     */
    public void append(Node control) {
         getChildren().add(control);
    }

    public int getWrappingWidth() {
        return wrappingWidth.get();
    }

    public IntegerProperty wrappingWidthProperty() {
        return wrappingWidth;
    }

    public void setWrappingWidth(int wrappingWidth) {
        this.wrappingWidth.set(wrappingWidth);
    }
}

The idea here is to leave text blocks which represent a paragraph by themselves as Text node. However if the paragraph contains some other node, it is splitt up into words. Thereby delegating the wrapping functionality to the underlying FlowPane.

While this solution here is not particularly sophisticated, it suffices my needs. Nevertheless I will replace it with TextFlow as soon as I migrate to Java 8.

JavaFX: Fixed size label

Though JavaFX provides a component for Pagination this is based on a fixed number of pages. However consider the following use case:

You have some text of undefined length but definitely longer than can fit on a page. The text is dynamic so it is not feasible to split up the text onto several pages. Further more it may be possible that while displaying the font or the font style changes and thereby resulting in a different paging of the text.

As I have just such a use case in OpenPatrician, I did a quick test on how such a thing could be implemented.

„JavaFX: Fixed size label“ weiterlesen

JavaFX: Perspective Transformation

As stated in one of my previous articles, the PerspectiveTransformation is good for transforming the visual repensentation of a node/shape, but its original position still stays the same. This means that if I want an transformed area to react on events (like mouse clicks), I have to transform the coordinates and then define the position.

„JavaFX: Perspective Transformation“ weiterlesen