Jul 15

TabPaneDetacher: Make your tabs detachable

I though it would be cool to detach e.g. the pane to publish messages in MQTT.fx if needed by just dragging the tab and dropping it at the wanted position to open its content as a dedicated new window.

drag tab

The TabPaneDetacher provides an easy to use way to enable the detach capability of with any JavaFX TabPane instance just by calling:

public class TabPaneDetacherDemoController {

    @FXML
    private TabPane demoTabPane;
    
    @FXML
    public void initialize() {
        TabPaneDetacher.create().makeTabsDetachable(demoTabPane);
    }    
    
}

The tab is removed from the tab pane and a new window is created containing the content of the tab, the window title is set to the tab name value. On closing that window the tab is restored at the original position:

Code can be found here in my Bitbucket repo.

Jul 10

UI logic with using JavaFX Bindings

For MQTT.fx I needed a ComboBox to enter new Topics or to choose recent topics from list.
But I want the user to enter or choose only (more or less) reasonable values otherwise the “Publish”/”Subscribe” buttons should be disabled:

ComboBox Bindings Demo 1

ComboBox Bindings Demo 2

Using the JavaFX Bindings API prevents some boilerplate code (implementing Listeners) and it is even more flexible as the result can be bound to several controls and at the end of the day its much more readable.

Contraint 1: The selection must not be empty.

  1. First create a JavaFX BooleanBinding.
  2. Then bind it to the disabledProperty of the button.

Contraint 2: Entered values must not contain only blanks (leading/trailing blanks can be trimmed later).

My approach is to

  1. add an EventFilter and to consume the event in case of only entered character is “SPACE”
  2. and if there are just blanks left when editing the value the content is cleared.
public class ComboBoxBindingsDemoController {

    @FXML
    private Label valueLabel;

    @FXML
    private Button goButton;

    @FXML
    private ComboBox<String> valueComboBox;

    private ObservableList<String> demoItemsList;
    private static final Pattern LEADING_BLANKS_PATTERN = Pattern.compile("^\\s*+");

    @FXML
    public void initialize() {
        valueComboBox.setItems(getDemoItemsList());

        BooleanBinding goButtonState = valueComboBox.editorProperty().get().textProperty().isEmpty()
                .or(valueComboBox.valueProperty().asString().isEmpty());

        goButton.disableProperty().bind(goButtonState);

        valueComboBox.getEditor().addEventFilter(KeyEvent.KEY_TYPED, (KeyEvent event) -> {
            Matcher matcher = LEADING_BLANKS_PATTERN.matcher(valueComboBox.getEditor().getText());
            if (" ".equals(event.getCharacter()) && valueComboBox.getEditor().getText().length() == 0) {
                event.consume();
            }
            else if(matcher.matches()){
                valueComboBox.getEditor().clear();
            }
        });

    }

    public ObservableList<String> getDemoItemsList() {
        if (demoItemsList == null) {
            demoItemsList = FXCollections.observableArrayList();
            demoItemsList.add("Erlangen");
            demoItemsList.add("Nürnberg");
            demoItemsList.add("Büchenbach");
        }
        return demoItemsList;
    }

    @FXML
    public void goAction() {
        System.out.println("Value '" + valueComboBox.getValue().trim() + "'");
    }

}

Complete runnable demo can be found at Bitbucket.

Jul 03

MQTT.fx 0.0.4 released

Just released new version of MQTT.fx.
Download binaries HERE.

MQTT.fx - v0.0.4

New:
- revisited UI (return of “real” buttons)
- extended support for $SYS-topics: subscription for mosquitto or Hive MQ can be choosen (in respect to @dobermai).
- publish and subcrive/receive are now different tabs
- experimental support for http-proxy (in respect to @dimaki123).
- last choosen broker & port is restored at next app start
- updated 3rd party libs (e.g. now using features of ControlsFX 8.0.6)
MQTT.fx - v0.0.4 - broker status
MQTT.fx - v0.0.4 - subscribe
MQTT.fx - v0.0.4 - connection options
MQTT.fx - v0.0.4 - validation

Fixed:
- publish to topics even if not subscribed before (in respect to @_efwe_)

Hint:
Configuration-format has changed, v0.0.4 might conflict with former versions.
In this case just delete (or rename) the mqttfx-config.xml.
Windows: [USER_HOME]\MQTT-FX\mqttfx-config.xml
OS X: [USER_HOME]/Library/Application Support/MQTT-FX/mqttfx-config.xml
The new configration is automatically created on next app start.

Jul 03

How to get rid of focus highlighting in JavaFX

Today I was asked if I know a way to get rid of the focus-highlighting of JavaFX controls (respectively buttons):

button_hover

Most posts and tipps regarding this issue suggesting to adding:

.button:focused {
    -fx-focus-color: transparent; 
}

But with this style a glow like this is still left:

button_glow

To get rid of this glow also often suggested to play around with -fx-background-insets additionally:

.button:focused {
    -fx-focus-color: transparent; 
    -fx-background-insets: -1.4, 0, 1, 2;
}

But this results in a button rendered with out an outer border:

button_insets

Compared to the default button style

button

this is still a kind of “highlighting”:

Why is that? (And why are there actually 4 inset values ?)
(note he comment of David Grieve below)

Having a look at the JavaFX default style as defined by modena.css bares some more information:

/* A bright blue for the focus indicator of objects. Typically used as the
* first color in -fx-background-color for the "focused" pseudo-class. Also
* typically used with insets of -1.4 to provide a glowing effect.
*/
-fx-focus-color: #f25f29;
-fx-faint-focus-color: #f25f2933;

Obviously there is not only one focus color -fx-focus-color but also -fx-faint-focus-color which is meant to create this glow-effect (that is remaining when setting -fx-focus-color:transparent;).

A closer look at the .button:focused pseudo class (in modena.css):

.button:focused {
    -fx-background-color: -fx-faint-focus-color, -fx-focus-color, -fx-inner-border, -fx-body-color; 
    -fx-background-insets: -2, -0.3, 1, 2;
    -fx-background-radius: 7, 6, 4, 3;
}

Playing around with some (extreme ;-)) colouring reveals the arrangement:

.button:focused {
    -fx-focus-color: red;
    -fx-faint-focus-color: green;
    -fx-inner-border: blue;
    -fx-body-color: orange;

    -fx-background-color: -fx-faint-focus-color, -fx-focus-color, -fx-inner-border, -fx-body-color; 
    -fx-background-insets: -2, -0.3, 1, 2;
    -fx-background-radius: 7, 6, 4, 3;
}

button_hover_style

Getting back to the topic maybe a clent way to remove the focus hightlight is to use the default button styles also for .button:focus (same approach for other controls):

.button:focused {
    -fx-background-color: -fx-outer-border, -fx-inner-border, -fx-body-color; 
    -fx-background-insets: 0, 1, 2;
    -fx-background-radius: 5, 4, 3;
}
Jun 26

At your Service!

The Service class (javafx.concurrency.Service) may not only be used to keep the UI reactive on long duration tasks but can also be used to change the state of controls or keep UI in a reasonable state on short term actions.

Recall that a Service is like a reusable Task. A Task can be executed once and has to be re-instantiated to be started again. The Service class creates a new Task each time it is (re-)started (createTask() is called then).

This is the start()-method from javafx.concurrency.Service class:

public void start() {

   checkThread();

    if (getState() != State.READY) {
        throw new IllegalStateException(
                "Can only start a Service in the READY state. Was in state " + getState());
    }

    // Create the task
    task = createTask();

    // Wire up all the properties so they use this task
    state.bind(task.stateProperty());
    value.bind(task.valueProperty());
    exception.bind(task.exceptionProperty());
    workDone.bind(task.workDoneProperty());
    totalWorkToBeDone.bind(task.totalWorkProperty());
    progress.bind(task.progressProperty());
    running.bind(task.runningProperty());
    message.bind(task.messageProperty());
	title.bind(task.titleProperty());

    // Advance the task to the "SCHEDULED" state
    task.setState(State.SCHEDULED);

    // Start the task
    executeTask(task);
}

Note that the properties binding of the Task (reset() is cleaning up all stuff).

In this post want to show how I’m using Services together with a JavaFX UI, like in MQTT.fx to connect or disconnect to a MQTT broker.

A simple connection pane with 5 controls:

connectionPane

Wanted appearance / behavior:
connectButton: only enabled if: not connected AND no service is running
disconnectButton: only enabled if: connected AND no service is running
cancelButton & progressIndicator: only visible if: any service is running
serviceMessageLabel: user feedback about the states of the services and the application

start

connecting

connected

disconnecting

The controller has two properties and contains two services (inner classes):

StringProperty statusMessagesProperty
BooleanProperty connectedProperty

ConnectService

private class ConnectService extends Service<Void> {

        @Override
        protected void succeeded() {
            statusMessagesProperty().set("Connected.");
            connectedProperty().set(true);
        }

        @Override
        protected void failed() {
            statusMessagesProperty().set("Connecting failed.");
            LOGGER.severe(getException().getMessage());
            connectedProperty().set(false);
        }

        @Override
        protected void cancelled() {
            statusMessagesProperty().set("Connecting cancelled.");
            connectedProperty().set(false);
        }

        @Override
        protected Task<Void> createTask() {
            return new Task<Void>() {
                @Override
                protected Void call() throws Exception {
                    updateMessage("Connecting....");
                    Thread.sleep(1000);
                    // DEMO: un-comment to provoke "Not on FX application thread"-Exception:
                    // connectButton.setVisible(false);
                    updateMessage("Waiting for server feedback.");
                    Thread.sleep(2000);
                    return null;
                }
            };
        }

    }

DisconnectService

    private class DisconnectService extends Service<Void> {

        @Override
        protected void succeeded() {
            statusMessagesProperty().set("");
            connectedProperty().set(false);
        }

        @Override
        protected void cancelled() {
            statusMessagesProperty().set("Disconnecting cancelled.");
            connectedProperty().set(false);
        }

        @Override
        protected Task<Void> createTask() {
            return new Task<Void>() {
                @Override
                protected Void call() throws Exception {
                    updateMessage("Disconnecting....");
                    Thread.sleep(1000);
                    updateMessage("Waiting for server feedback.");
                    Thread.sleep(2000);
                    return null;
                }
            };
        }

    }

The wanted UI-behavior can be accomplished just by some Bindings

BooleanBinding anyServiceRunning = connectService.runningProperty().or(disconnectService.runningProperty());
serviceRunningIndicator.visibleProperty().bind(anyServiceRunning);
cancelButton.visibleProperty().bind(anyServiceRunning);
connectButton.disableProperty().bind(connectedProperty().or(anyServiceRunning));
disconnectButton.disableProperty().bind(connectedProperty().not().or(anyServiceRunning));
messagesLabel.textProperty().bind(statusMessagesProperty());

ChangeListeners are passing the messages from the services to the statusMessagesProperty:

connectService.messageProperty().addListener((ObservableValue observableValue, String oldValue, String newValue) -> {
statusMessagesProperty().set(newValue);
});
disconnectService.messageProperty().addListener((ObservableValue observableValue, String oldValue, String newValue) -> {
statusMessagesProperty().set(newValue);
});

Three methods to control the services:

   @FXML
    public void cancel() {
        LOGGER.info("cancel");
        connectService.cancel();
        disconnectService.cancel();
    }

    @FXML
    public void connect() {
        LOGGER.info("connect");
        disconnectService.cancel();
        connectService.restart();
    }

    @FXML
    public void disconnect() {
        LOGGER.info("disconnect");
        connectService.cancel();
        disconnectService.restart();
    }

Nice & convenient:
Instead of verifying the state of the Service you can just call restart().
restart() executes:
1. cancel() (if running): cancel the executed service-task
2. reset(): clear the Service (task=null and unbind all stuff)
and then
3. start(): create new Task and bind its properties

You can get the complete code of this tutorial in my BitBucket repo:

ServiceDemoApp
https://bitbucket.org/Jerady/servicedemoapp/src

Jun 14

MQTT.fx 0.0.3 released

Most significant change: I have added a pane to show some status values of the broker:

mqtt-0.0.3

In v0.0.3 these $SYS topics are recognised (Tooltips are showing the descriptions):

Version: $SYS/broker/version
Build: $SYS/broker/timestamp
Uptime: $SYS/broker/uptime
Subscriptions Count: $SYS/broker/subscriptions/count
Changeset: $SYS/broker/changeset
Clients Connected: $SYS/broker/clients/active
Clients Expired: $SYS/broker/clients/expired
Clients Disconnected: $SYS/broker/clients/inactive
Clients Maximum: $SYS/broker/clients/maximum
Clients Total: $SYS/broker/clients/total
Connection: $SYS/broker/connection/#
Messages Inflight: $SYS/broker/messages/inflight
Messages Received: $SYS/broker/messages/received
Messages Sent: $SYS/broker/messages/sent
Messages Stored: $SYS/broker/messages/stored
Messages Publish Dropped: $SYS/broker/publish/messages/dropped
Messages Publish Received: $SYS/broker/publish/messages/received
Messages Publish Sent: $SYS/broker/publish/messages/sent
Messages Retained Count: $SYS/broker/retained/messages/count
Bytes Received: $SYS/broker/bytes/received
Bytes Sent: $SYS/broker/bytes/sent
Load Connections: $SYS/broker/load/connections/+
Load Bytes Received: $SYS/broker/load/bytes/received/+
Load Bytes Sent: $SYS/broker/load/bytes/sent/+
Load Messages Received: $SYS/broker/load/messages/received/+
Load Messages Sent: $SYS/broker/load/messages/sent/+
Load Publish Dropped: $SYS/broker/load/publish/dropped/+
Load Publish Received: $SYS/broker/load/publish/received/+
Load Publish Sent: $SYS/broker/load/publish/sent/+
Load Sockets Count: $SYS/broker/load/sockets/+

Download binaries:
Mac OSX DMG
Windows 32bit Installer
Zipped executable jar

May 21

FontAwesomeFX 8.0.7/8.0.8 released

UPDATE: In 8.0.7 I forgot to replace the TTF! So 8.0.7 still contains the 4.0.1 font. Some icons may not be displayed with 8.0.7. Have fixed this issue with fontawesomefx-8.0.8.

NavigationButtonsI have updated FontAwesomeFX and released version 8.0.7.
A few days ago the FontAwesome 4.1.0 was released with 70+ additional icons (FontAwesome now contains 439 icons).

Download Binaries
Sources @ Bitbucket

Maven Artifact:

<dependency>
  <groupId>de.jensd</groupId>
  <artifactId>fontawesomefx</artifactId>
  <version>8.0.8</version>
</dependency>
May 16

“somehow more organic”: how to create a ‘noisy’ gradient in JavaFX

If you always wondered why some regions on your Mac, Websites or in your Smartphone-Apps look somehow more organic than a plain coloured area or even an region with a gradient, have a closer look!
Zooming into these areas shows that they are a bit “noisy”.

This effect can be created very easily with CSS in JavaFX too:
I just noticed that “-fx-background-image” is painted in front of “-fx-background-color“:

javafx_css_color_paint

So, what is needed is a transparent “noise texture” which can be created here or here.

This texture is then used as a repeated background-image and painted in front the background-color which in JavaFX-CSS can also be a linear gradient:

-fx-background-color: linear-gradient(rgb(224,228,233) 0%, derive(rgb(224,228,233),-20%) 100%);
-fx-background-image: url("images/noise-texture.png");
-fx-background-repeat: repeat;  

I used this approach e.g in my MQTT.fx-UI:

mqtt-fx-6-noise-0.0.2

May 14

MQTT.fx 0.0.2

A new version of MQTT.fx is available and I have polished the pre-alpha version and added some new features to MQTT.fx.

Download binaries:
Mac OSX DMG
Windows 32bit Installer
Zipped executable jar

The Video for Jim Weaver’s “Real World Apps” talk @GeeCon2014 in Kraków

Controls to connect to the broker and to subscribe to topics are now placed in the header:

mqtt-fx-1-0.0.2

“Connection Options” can be reached from here:

mqtt-fx-2-0.0.2

“Publish” and “Receive” are place in one tab:

mqtt-fx-3-0.0.2

I have added an option to enable notifications on received messages:

mqtt-fx-3-2-0.0.2

AND NEW: “Arrived Messages” are collected in a separate tab with one color by topic.
The related messaged are colored accordingly thus they can be easily identified:

mqtt-fx-4-0.0.2

Also I found out an easy way to apply a noise and gradient effect via CSS like this:

mqtt-fx-6-noise-0.0.2

May 09

JavaFX based MQTT Testing Utility

New Version: MQTT.fx 0.0.2

Now that MQTT is on its way to become THE industry-standard protocol for IoT and M2M communication the IoT community might have to review current message strategies.

Isn’t it a very good way to start with a JavaFX-Client to get into MQTT ;-)?
So, currently I am working on JavaFX based frontend based on Eclipse Paho.

Featured so far:

  • connect to an MQTT broker (tested with mosquitto yet)
  • modify some connection options
  • subscribe to topics
  • publish to topics
  • continuous logging of arrived messages
  • load and save settings (working directory: [user.home]/mqttfx)
  • an ugly application icon

Like to give it a try?
Download executable JAR (with dependencies) (requires an installed Java8-JRE)
Download Mac OSX DMG
Download Windows (x86) Installer

Main Screen
mqtt-fx-1

Logging Arrived-Messages
mqtt-fx-2

Editing Connection Options
mqtt-fx-3

Stored Configuration and UI-Settings
mqtt-fx-4