Sending notification with javafx without stage


Question

You can send a desktop notification with JavaFx like this (requires jdk 8u20 or later):

package sample;

import javafx.application.Application;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.stage.Stage;
import org.controlsfx.control.Notifications;

public class Main extends Application {

    @Override
    public void start(Stage primaryStage) throws Exception{
//        Parent root = FXMLLoader.load(getClass().getResource("sample.fxml"));
        Button notifyButton = new Button("Notify");
        notifyButton.setOnAction(e -> {
            Notifications.create().title("Test").text("Test Notification!").showInformation();
        });
        primaryStage.setTitle("Hello World");
        primaryStage.setScene(new Scene(notifyButton, 100, 50));
        primaryStage.show();
    }


    public static void main(String[] args) {
        launch(args);
    }
}

But this way you have to create a main window (stage), is it possible to avoid this? I am looking for a way to send notification like using zenity in bash: most of the code is non-gui, but uses some gui elements for informing or interacting with user in a very basic fashion.

1
2
11/11/2014 10:03:15 PM

Accepted Answer

It looks like the ControlsFX notifications require a existing stage. You can create a hidden utility stage. Try something like this.

package sample;

import javafx.application.Application;
import javafx.application.Platform;
import javafx.embed.swing.JFXPanel;
import javafx.scene.Scene;
import javafx.scene.layout.StackPane;
import javafx.scene.paint.Color;
import javafx.stage.Stage;
import javafx.stage.StageStyle;
import org.controlsfx.control.Notifications;

public class Main extends Application {

    @Override
    public void start(Stage primaryStage) throws Exception{
    }


    public static void main(String[] args) {
        new JFXPanel();
        notifier("Good!", "It's working now!");
    }

    private static void notifier(String pTitle, String pMessage) {
        Platform.runLater(() -> {
                    Stage owner = new Stage(StageStyle.TRANSPARENT);
                    StackPane root = new StackPane();
                    root.setStyle("-fx-background-color: TRANSPARENT");
                    Scene scene = new Scene(root, 1, 1);
                    scene.setFill(Color.TRANSPARENT);
                    owner.setScene(scene);
                    owner.setWidth(1);
                    owner.setHeight(1);
                    owner.toBack();
                    owner.show();
                    Notifications.create().title(pTitle).text(pMessage).showInformation();
                }
        );
    }
}

new JFXPanel() initializes the JavaFX thread without having to extend Application. You have to call this before any calls to Platform.runLater() otherwise you will get a thread exception. You only need to call it once for the whole application though. Honestly it is probably better to create your own notification stage and display it directly. Create a stage like above and put your own contents. You can probably reuse some of the styling from the ControlsFX source.

6
11/12/2014 12:47:33 AM

Licensed under: CC-BY-SA with attribution
Not affiliated with: Stack Overflow
Icon