简体   繁体   中英

How to correctly put a dialog inside animation timer in JavaFX

I have an animation timer and when i handle the end, if a certain condition is true, i want to show a dialog to the user. When i simply tried to call the dialog after the stop() method i had this exception (only on mobile):

java.lang.IllegalStateException: Cannot enter nested loop during animation or layout processing

So, for this case, i solved it wrapping the dialog inside Platform.runLater() method.

Is this the correct way to handle this case?

If not, which is the correct one?

The dialog i'm using is gluon dialog:

http://docs.gluonhq.com/charm/javadoc/4.2.0/com/gluonhq/charm/glisten/control/Dialog.html

And on this simply show doesn't exist, there's only show and wait.

I've added an Alert inside an AnimationTimer to reproduce the issue:

private long count = 0;

public BasicView(String name) {
    super(name);

    AnimationTimer timer = new AnimationTimer() {
        private long time;

        @Override
        public void handle(long now) {
            if (now - time > 1_000_000_000) {
                count++;
                if (count == 5) {
                    Alert alert = new Alert(Alert.AlertType.INFORMATION, "Hi there");
                    alert.showAndWait();
                }
                time = now;
            }

        }
    };

    setCenter(new StackPane(new Label("Hello JavaFX World!")));

    setOnShown(e -> timer.start());
    setOnHidden(e -> timer.stop());
}

This fails whether you choose javafx.scene.control.Alert :

Exception in thread "JavaFX Application Thread" java.lang.IllegalStateException: showAndWait is not allowed during animation or layout processing
at javafx.scene.control.Dialog.showAndWait(Dialog.java:328)

or com.gluonhq.charm.glisten.control.Alert :

Exception in thread "JavaFX Application Thread" java.lang.IllegalStateException: Cannot enter nested loop during animation or layout processing
at com.sun.javafx.tk.quantum.QuantumToolkit.enterNestedEventLoop(QuantumToolkit.java:570)
at com.gluonhq.charm.glisten.control.Dialog.a(SourceFile:613)

and whether you run it on desktop or Android:

04-05 17:50:48.289  9592  9627 E AndroidRuntime: java.lang.IllegalStateException: Cannot enter nested loop during animation or layout processing
04-05 17:50:48.289  9592  9627 E AndroidRuntime:    at com.sun.javafx.tk.quantum.QuantumToolkit.enterNestedEventLoop(QuantumToolkit.java:585)
04-05 17:50:48.289  9592  9627 E AndroidRuntime:    at com.gluonhq.charm.glisten.control.Dialog.a(SourceFile:613)

The Dialog implementation (JavaFX/Gluon) makes use of Toolkit.getToolkit().enterNestedEventLoop() , and if you check the Quantum implementation :

if (!canStartNestedEventLoop()) {
    throw new IllegalStateException("Cannot enter nested loop during animation or layout processing");
}

If you try this inside the animation:

@Override
public void handle(long now) {
    System.out.println("In pulse: " + !Toolkit.getToolkit().canStartNestedEventLoop()); 
}

you will see that inside the animation your pulse is true: by definition of an animationTimer, handle is called precisely on every pulse!

So you can't enter a nested event loop, unless you avoid the call on that instant. Platform.runLater() it's just a way to do it a little bit later .

So this will work fine:

@Override
public void handle(long now) {
        if (now - time > 1_000_000_000) {
            count++;
            if (count == 5) {
                Alert alert = new Alert(AlertType.INFORMATION, "Hi there");
                Platform.runLater(alert::showAndWait);
            }
            time = now;
        }
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM