how can one detect a finished resizing operation in JavaFX?
Asked Answered
S

3

7

I have a stage, a scene and a WebView node. When I expand the window to a larger size - things get pretty sluggish due to WebView. What I want to do is fill the new space for WebView only when the resizing of the window has been finished (this is me releasing left mouse button on the resizable control/edge of the window). For now I can just set the max. size of this node to what it is by default - this will stop it from expansion. But how can I detect the actual event of a completed resizing operation on the window? With binding, I can verify that the resizing takes place - but it's instantaneous (properties for W & D change immediately w/o releasing LMB), while I only require an action when the LMB has been released. Suggestions?


I tried using an addEventFilter on the stage for Event.ANY, just to see if this event type is recognizable - sadly with no avail.

I've also stumbled upon this unanswered post.

Stearns answered 7/7, 2012 at 18:33 Comment(3)
What is the parent of webview?Martguerita
javafx.scene.Scene, but I can add whatever inbetween (any Pane)Stearns
i created an answer (including code!) for this here: #10773500Zahara
T
4

This answer is only applies if you are able to use an undecorated Stage for your application.

With an undecorated stage you can handle the resizing decorations and operations yourself; allowing access to the right hooks for handling the completion of a resize operation.

See the WindowResizeButton class in the Ensemble sample application source code for a demo of how to implement a resize handle for an undecorated stage. Modify this class to add a setOnMouseReleased handler and implement your webView size modifications in there.

I do wonder why this is necessary though as I haven't really had any sluggishness resizing a Window containing WebView - perhaps this is due to your app having different content usage in the WebView from what I have been using.

Toplofty answered 8/7, 2012 at 6:42 Comment(2)
Great advice, thank you. I have done exactly that. Shame though that there seems to be no easy way of overriding the default stage's event handler. Regarding WebView - this is really a problem, I can't even say that the sample provided by Oracle (which leads to the same corporate site) is 100% smooth in scrolling (it's laggy by a tiny fraction though).Stearns
For future readers, the WindowResizeButton class can be found in the JavaFX 2 samples. It doesn't seem to exist in the Java7/8 samples.Straightaway
M
3

This is not a direct answer to your question. If I understood the sluggishness correctly you are facing somekind weird flashings and renderings. To reduce the sluggishness the size of the webView can be updated manually and more sparsely:

import javafx.animation.KeyFrame;
import javafx.animation.Timeline;
import javafx.application.Application;
import javafx.beans.value.ChangeListener;
import javafx.beans.value.ObservableValue;
import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.scene.Scene;
import javafx.scene.layout.Pane;
import javafx.scene.layout.PaneBuilder;
import javafx.scene.web.WebView;
import javafx.stage.Stage;
import javafx.util.Duration;

public class KSO_Demo extends Application {

    @Override
    public void start(Stage primaryStage) {

        final WebView webView = new WebView();
        webView.getEngine().loadContent("<div style='background-color: gray; height: 100%'>Some content</div>");

        final Pane pane = PaneBuilder.create().children(webView).style("-fx-border-color: blue").build();

        final Timeline animation = new Timeline(
                new KeyFrame(Duration.seconds(.5),
                new EventHandler<ActionEvent>() {

                    @Override
                    public void handle(ActionEvent actionEvent) {
                        webView.setPrefSize(pane.getWidth(), pane.getHeight());
                    }
                }));
        animation.setCycleCount(1);

        primaryStage.setScene(new Scene(pane, 300, 250));

        primaryStage.widthProperty().addListener(new ChangeListener<Number>() {
            @Override
            public void changed(ObservableValue<? extends Number> arg0, Number arg1, Number arg2) {
                animation.play();
            }
        });

        primaryStage.heightProperty().addListener(new ChangeListener<Number>() {
            @Override
            public void changed(ObservableValue<? extends Number> arg0, Number arg1, Number arg2) {
                animation.play();
            }
        });
        primaryStage.show();
    }

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

The webView is in the Pane which does not layout its children automatically. The webView's size updating is delayed for .5 second ignoring updates in interval.

Martguerita answered 7/7, 2012 at 23:24 Comment(1)
It's not really the weird flashings - it's just that the resizing operation looks painful (slow), as it stutters (lags) when the size of the window is changed and WebView is forced to expand accordingly. Anyhow, even though as you state yourself this answer does not address a direct solution - it is still an interesting approach. Thank you kindly for input.Stearns
G
-1

I am making an application where I have to periodically fetch satellite imagery (rather intensive), so I had to find a way to capture only the last event as well. I settled on spawning a thread to count down for some length of time before executing the intensive task and a resize-listener that resets the count. It seems more efficient to me than scheduling and unscheduling tasks hundreds of times.

Note I've also got some logic in here to capture the first window-size-change with System.currentTimeMillis();

import javafx.application.Platform;
import javafx.beans.value.ChangeListener;
import javafx.beans.value.ObservableValue;

public class ResizeListener implements ChangeListener {
    long lastdragtime = System.currentTimeMillis();
    double xi, yi, dx, dy, wid, hei;
    GuiModel model;
    TimerThread timebomb;

    public ResizeListener(GuiModel model) {
        this.model = model;
        timebomb = new TimerThread(350);
        timebomb.start();
    }

    public void changed(ObservableValue observable, Object oldValue, Object newValue) {
        if (System.currentTimeMillis() - lastdragtime > 350) { //new drag
            xi = model.stage.getWidth();
            yi = model.stage.getHeight();
            model.snapshot = model.canvas.snapshot(null, null);
        }

        timebomb.active = true;//start timer
        timebomb.ms = timebomb.starttime;//reset timer

        wid = model.stage.getWidth()-72;
        hei = model.stage.getHeight()-98;
        dx = model.stage.getWidth() - xi;
        dy = model.stage.getHeight() - yi;
        if (dx < 0 && dy < 0) {
            model.canvas.setWidth(wid);
            model.canvas.setHeight(hei);
            model.graphics.drawImage(model.snapshot, -dx/2, -dy/2, wid, hei, 0, 0, wid, hei);
        } else if (dx < 0 && dy >= 0) {
            model.canvas.setWidth(wid);
            model.graphics.drawImage(model.snapshot, -dx/2, 0, wid, hei, 0, 0, wid, hei);
        } else if (dx >= 0 && dy < 0) {
            model.canvas.setHeight(hei);
            model.graphics.drawImage(model.snapshot, 0, -dy/2, wid, hei, 0, 0, wid, hei);
        }
        lastdragtime = System.currentTimeMillis();
    }

    private class TimerThread extends Thread {
        public final int starttime;//multiple of 25
        public int ms = 0;
        public boolean active = false;

        public TimerThread(int starttime) {
            this.setDaemon(true);
            this.starttime = starttime;
        }

        public void run() {
            while (true) {
                try {
                    Thread.sleep(25);
                } catch (InterruptedException x) {
                    break;
                }

                if (active) {
                    ms -= 25;
                    if (ms <= 0) {
                        active = false;
                        Platform.runLater(() -> {
                            model.canvas.setWidth(wid);
                            model.canvas.setHeight(hei);
                            model.fetchSatelliteImagery();
                            model.refresh();
                        });
                    }
                }
            }
        }
    }//end TimerThread class
}//end listener class
Garcon answered 22/4, 2015 at 18:33 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.