当用户释放鼠标左键时,获取单阶段调整大小事件 [英] Get single stage resize event when user releases left mouse button

查看:134
本文介绍了当用户释放鼠标左键时,获取单阶段调整大小事件的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我已经足够google了,但仍然可以找到解决方案,只有当用户释放鼠标左键时才能获得单个调整大小事件。例如,来自此处的以下解决方案

I've googled enough but still can find solution to get only single resize event when user releases left mouse button. For example the following solution from here

stage.titleProperty().bind(
        scene.widthProperty().asString().
        concat(" : ").
        concat(scene.heightProperty().asString()));

当用户点击鼠标左键并开始调整舞台大小时,我们将获得很多事件(使用属性侦听器) )虽然他确实调整了大小。但是,我想只获得一个事件 - 当用户完成调整大小并释放鼠标左键时。

When user clicks mouse left button and starts resizing the stage we will get very many events (using property listeners) while he does resizing. However, I want to get only one event - when the user completes resizing and releases mouse left button.

另一个解决方案是此处此解决方案显着减少了事件的数量,但仍然不允许只获得一个。

Another solution is here This solution significantly decreases amount of events but still doesn't let to get only one.

如何在用户释放鼠标按钮后只获得一个调整大小事件?

How to get only one resize event after user releases mouse button?

推荐答案

据我所知,调整阶段大小的鼠标事件处理程序是本机管理的,因此无法纯粹在JavaFX中访问它们 - 为此,您所描述的方式需要编写本机库并挂钩它们。

As far as I know, the mouse event handlers that resize the stage are managed natively, and so there is no way to access those purely in JavaFX - to do this the way you describe would require writing native libraries and hooking into them.

如果你正在做一些繁重的计算(或其他需要很长时间的工作)以响应舞台大小的变化,你最好的选择可能是编写一次只处理一个更改的代码,并在可能的情况下处理最后一次已知的更改。

If you are doing some heavy computation (or other work that takes a long time) in response to the change in size of the stage, your best bet is probably to write code that only processes one change at a time, and just processes the last known change when it can.

这方面的一个例子是:

import java.util.Random;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.BlockingQueue;

import javafx.application.Application;
import javafx.application.Platform;
import javafx.beans.value.ChangeListener;
import javafx.geometry.Point2D;
import javafx.scene.Scene;
import javafx.scene.layout.StackPane;
import javafx.stage.Stage;

public class StageResizeThrottling extends Application {

    private Random rng = new Random();

    @Override
    public void start(Stage primaryStage) {

        BlockingQueue<Point2D> dimensionChangeQueue = new ArrayBlockingQueue<>(1);
        ChangeListener<Number> dimensionChangeListener = (obs, oldValue, newValue) -> {
            dimensionChangeQueue.clear();
            dimensionChangeQueue.add(new Point2D(primaryStage.getWidth(), primaryStage.getHeight()));
        };
        primaryStage.widthProperty().addListener(dimensionChangeListener);
        primaryStage.heightProperty().addListener(dimensionChangeListener);

        Thread processDimensionChangeThread = new Thread(() -> {
            try {
                while (true) {
                    System.out.println("Waiting for change in size");
                    Point2D size = dimensionChangeQueue.take();
                    System.out.printf("Detected change in size to [%.1f, %.1f]: processing%n", size.getX(), size.getY());
                    process(size, primaryStage);
                    System.out.println("Done processing");
                }
            } catch (InterruptedException letThreadExit) { }
        });
        processDimensionChangeThread.setDaemon(true);
        processDimensionChangeThread.start();

        Scene scene = new Scene(new StackPane(), 600, 600);
        primaryStage.setScene(scene);
        primaryStage.show();
    }

    private void process(Point2D stageDimension, Stage stage) throws InterruptedException {
        // simulate slow process:
        Thread.sleep(500 + rng.nextInt(1000));
        final String title = String.format("Width: %.0f Height: %.0f", stageDimension.getX(), stageDimension.getY());
        Platform.runLater(() -> stage.setTitle(title));
    }

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

请注意,这将始终处理第一次更改,然后在每个先前处理的更改已完成处理时处理最新更改。如果没有进一步的更改,它将等待一个确实发生,然后立即处理。如果您愿意,可以将此与您链接的基于计时器的技术结合起来,以便合并监听器中的更改,这通常会删除处理的第一个更改(这通常是多余的,因为它几乎总是跟随后续更改) 。以下更改将等待,直到300ms没有发生调整,然后将其提交到队列进行处理(线程仍然以相同的方式运行 - 它将处理最新的更改,并且当处理完成时,等待另一个):

Note that this will always process the very first change immediately, and then process the latest change when each previously-processed change has finished processing. If no further changes have occurred, it will wait until one does occur and then process it immediately. If you like, you can combine this with the timer-based technique you linked for coalescing the changes in the listener, which will typically remove the very first change that is processed (which is usually redundant as it is almost always followed by subsequent changes). The following changes will wait until no resizes have occurred for 300ms before submitting one to the queue for processing (the thread still behaves the same way - it will process the latest change, and when that processing is complete, wait for another one):

    BlockingQueue<Point2D> dimensionChangeQueue = new ArrayBlockingQueue<>(1);

    PauseTransition coalesceChanges = new PauseTransition(Duration.millis(300));
    coalesceChanges.setOnFinished(e -> {
        dimensionChangeQueue.clear();
        dimensionChangeQueue.add(new Point2D(primaryStage.getWidth(), primaryStage.getHeight()));           
    });

    ChangeListener<Number> dimensionChangeListener = (obs, oldValue, newValue) -> 
        coalesceChanges.playFromStart();

    primaryStage.widthProperty().addListener(dimensionChangeListener);
    primaryStage.heightProperty().addListener(dimensionChangeListener);

这里有一些调整,这是延迟和处理变更过度渴望之间的权衡。您可能希望暂停转换持续时间比屏幕大小更改的平均处理时间短,但不会缩短一个数量级。

There's some tuning here, which is a tradeoff between latency and over-eagerness in processing changes. You probably want the pause transition to last something shorter than the average processing time of the change in screen size, but not an order of magnitude shorter.

代码保证不会将一次处理多个更改,如果不再发生更改,最终将更新最新更改。这可能与您在不访问本机用户事件的情况下一样好。 (它还会处理舞台大小的程序化更改,鼠标处理程序无法处理。)

The code guarantees that no more than one change will be processed at a time and that the latest change will eventually be processed if no more changes occur. This is probably about as good as you can get without accessing native user events. (And it would also handle programmatic changes in the stage size, which a mouse handler would not handle.)

这篇关于当用户释放鼠标左键时,获取单阶段调整大小事件的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆