Как создать всплывающее окно уведомления, прозрачное для мыши?

Задача

Я хотел бы создать окно уведомлений, прозрачное для мыши на сцене и на рабочем столе.

Проблема

Всплывающее окно не имеет прозрачности для мыши. Когда отображается всплывающее окно, вам нужно подождать, пока оно не исчезнет, ​​чтобы получить доступ к содержимому за ним.

Вопрос

Можно ли создавать всплывающие окна уведомлений (или другие окна) с механизмом перехода по клику? Это должно работать для всплывающих окон на сцене и всплывающих окон на рабочем столе.

Код

Вот пример кода, который создает уведомление при нажатии на кнопку. Всплывающее окно исчезает через 3 секунды. После этого вы можете нажать кнопку еще раз.

import javafx.animation.KeyFrame;
import javafx.animation.Timeline;
import javafx.application.Application;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.Label;
import javafx.scene.layout.StackPane;
import javafx.stage.Popup;
import javafx.stage.Stage;
import javafx.util.Duration;

public class Notification extends Application {

    static double width = 800;
    static double height = 600;
    static int counter = 0;

    Stage stage;

    @Override
    public void start(Stage stage) {

        this.stage = stage;

        // content area
        StackPane root = new StackPane();
        root.setStyle("-fx-background-color:white");

        // button which shows a popup
        Button notificationButton = new Button("Add Popup");
        notificationButton.setOnAction(e -> {
            addNotification("This is notification nr. " + (++counter));
        });

        root.getChildren().add(notificationButton);

        Scene scene = new Scene(root, width, height);

        stage.setScene(scene);
        stage.show();

    }

    private void addNotification(String message) {

        // create popup content
        Label messageLabel = new Label(message);

        final StackPane content = new StackPane();
        content.setPrefSize(200, 200);
        content.setStyle("-fx-background-color:lightgrey");
        content.setOpacity(0.5);
        content.setMouseTransparent(true);

        content.getChildren().addAll(messageLabel);

        // create popup and show it
        final Popup popup = new Popup();
        popup.setX(stage.getX() + (stage.getScene().getWidth() - 200) / 2);
        popup.setY(stage.getY() + (stage.getScene().getHeight() - 200) / 2);
        popup.getContent().add(content);

        popup.show(stage.getScene().getWindow());

        // hide popup after 3 seconds
        Duration displayDuration = Duration.millis(3000);
        KeyFrame displayDurationKeyFrame = new KeyFrame(displayDuration);

        Timeline timeline = new Timeline(displayDurationKeyFrame);
        timeline.setOnFinished(e -> {
            popup.hide();
        });
        timeline.play();

    }

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

}

person Roland    schedule 09.02.2016    source источник


Ответы (1)


Попробуйте это вместо этого. Я удалил initModality(), потому что это блокировало доставку событий ввода в другое окно. Я также добавил прослушиватель, чтобы новая сцена вообще не сфокусировалась.

final Stage popup = new Stage();
popup.setX(stage.getX() + (stage.getScene().getWidth() - 200) / 2);
popup.setY(stage.getY() + (stage.getScene().getHeight() - 200) / 2);
popup.setScene(new Scene(content));
popup.initOwner(stage);
popup.focusedProperty().addListener(new ChangeListener<Boolean>() {
    @Override
    public void changed(ObservableValue<? extends Boolean> observable, Boolean oldValue, Boolean newValue) {
        stage.requestFocus();
    }
});
popup.initStyle(StageStyle.TRANSPARENT);
popup.setOpacity(0.5);
popup.show();

javafx

person Marian    schedule 09.02.2016
comment
Спасибо, но, похоже, это не работает в Windows 7, Java 8u65. Тот же эффект, всплывающие блоки. Однако с новым этапом возникает другая проблема: когда пользователь e. грамм. типы, пока вы показываете всплывающее окно, новый этап получает фокус. Он должен отображать только уведомление, но пользователь должен иметь возможность продолжать печатать. - person Roland; 10.02.2016
comment
Спасибо, теперь фокус работает, но основная проблема осталась. Я все еще не могу нажать кнопку, пока всплывающее окно не исчезнет. Это действительно работает для вас? Какую систему и версию Java вы используете? - person Roland; 10.02.2016
comment
Это то же самое, что и ваша система. Что происходит, если узел на родительском этапе находится непосредственно за всплывающим окном, события мыши не попадают на этот конкретный узел. Но всплывающее окно не прерывает и не препятствует вводу текста или щелчку, если всплывающее окно не находится непосредственно над определенной кнопкой или текстовым полем, которое вы пытаетесь щелкнуть или использовать. - person Marian; 10.02.2016
comment
Да и у меня именно такая проблема. Код в вопросе уже способен отображать уведомление, не отвлекая внимание. Это просто MCVE. Вы можете добавить TextArea и PauseTransition с помощью 3 с, ввести TextArea, и после 3 с появится уведомление без кражи фокуса. Проблема в том, что когда кто-то e. грамм. пытается прокрутить. Никто не хочет нажимать на полосу прокрутки, и вдруг появляется какое-то всплывающее окно, которое ловит щелчок. Я знаю, не перекрывайте его полосой прокрутки, но мне нужно общее решение. Даже если мне придется использовать JNI. - person Roland; 11.02.2016