如何知道窗口的大小调整是从左还是从右进行



我正在使用JavaFX构建GUI,在调整鼠标大小时,我在知道鼠标位置方面遇到了问题。其想法是,如果鼠标位于GUI的边缘,它将变为一个双面箭头,指示您现在可以按下鼠标并调整窗口大小。

我需要鼠标指针在此边缘的位置,但我不知道如何做到这一点。我需要知道窗口的大小调整方向。

更新添加了新选项并讨论了优缺点。

这很棘手。问题是窗口会跟踪其顶部、左侧、宽度和高度。当它从右边或底部调整大小时,事情很容易:宽度或高度会发生变化。但当从左侧调整其大小时,x和宽度都必须更改。这两个变化不是原子性的,因为x和width存储为两个独立的属性。

第一种方法是跟踪鼠标坐标,看看它是在左半部分还是在右半部分。(很明显,你可以对高度做同样的事情。)这种方法与任何实现细节无关,但用户可能会因为非常小心地使用鼠标而导致它失败。如果将鼠标移动到窗口的右边缘,精确到窗口边界的像素,然后调整大小,则可能会看到不正确的输出。

import javafx.application.Application;
import javafx.stage.Stage;
import javafx.scene.Scene;
import javafx.scene.layout.BorderPane;
public class Main extends Application {
    @Override
    public void start(Stage primaryStage) {
        BorderPane root = new BorderPane();
        Scene scene = new Scene(root,400,400);
        class MouseLocation {
            double x,y ;
        }
        MouseLocation mouseLocation = new MouseLocation();
        scene.setOnMouseMoved(event -> {
            mouseLocation.x = event.getX();
            mouseLocation.y = event.getY();
        });
        primaryStage.widthProperty().addListener((obs, oldWidth, newWidth) -> {
            if (mouseLocation.x < primaryStage.getWidth() / 2) {
                System.out.println("Resized from left");
            } else {
                System.out.println("Resized from right");
            }
        });
        primaryStage.setScene(scene);
        primaryStage.show();
    }
    public static void main(String[] args) {
        launch(args);
    }
}

第二种方法是跟踪窗口的最后一个已知水平范围(minX和maxX),并在宽度变化时更新该范围。然后您可以检查minX或maxX是否已更改。这种方法的问题在于它依赖于未记录的实现细节。它显示(在我的系统上,使用当前版本等),当从左侧调整窗口大小时,首先更改x,然后更改宽度。如果在随后的版本中发生变化,以下内容将被破坏:

import javafx.application.Application;
import javafx.stage.Stage;
import javafx.scene.Scene;
import javafx.scene.layout.BorderPane;
public class Main extends Application {
    @Override
    public void start(Stage primaryStage) {
        BorderPane root = new BorderPane();
        Scene scene = new Scene(root,400,400);
        class MutableDouble {
            double value ;
        }
        MutableDouble windowLeftEdge = new MutableDouble();
        primaryStage.widthProperty().addListener((obs, oldWidth, newWidth) -> {
            if (primaryStage.getX() == windowLeftEdge.value) {
                System.out.println("Resized from right");
            } else {
                System.out.println("Resized from left");
            }
            windowLeftEdge.value = primaryStage.getX() ;
        });
        primaryStage.setScene(scene);
        primaryStage.show();
    }
    public static void main(String[] args) {
        launch(args);
    }
}

第三种方法(我能想到)是将快速发生的变化合并为一个单一的变化。这对于正确编程来说有点棘手,所以我没有从头开始,而是使用了第三方ReactFX框架,该框架对"事件流"进行建模,并有一个内置机制来组合快速连续发生的事件。这可能是本文提出的三种解决方案中最稳健的一种,但代价是一定程度的复杂性或包含外部框架。

import java.time.Duration;
import org.reactfx.Change;
import org.reactfx.EventStream;
import org.reactfx.EventStreams;
import javafx.application.Application;
import javafx.beans.binding.Bindings;
import javafx.beans.value.ObservableValue;
import javafx.geometry.BoundingBox;
import javafx.geometry.Bounds;
import javafx.scene.Scene;
import javafx.scene.layout.BorderPane;
import javafx.stage.Stage;
public class ReactFXVersion extends Application {
    @Override
    public void start(Stage primaryStage) {
        BorderPane root = new BorderPane();
        Scene scene = new Scene(root,400,400);
        ObservableValue<Bounds> windowBounds = Bindings.createObjectBinding(() -> 
            new BoundingBox(primaryStage.getX(), primaryStage.getY(), primaryStage.getWidth(), primaryStage.getHeight()), 
            primaryStage.xProperty(), primaryStage.yProperty(), primaryStage.widthProperty(), primaryStage.heightProperty());
        EventStream<Change<Bounds>> bounds = EventStreams.changesOf(windowBounds)
                .reduceSuccessions((previousChange,  nextChange) -> 
                    new Change<>(previousChange.getOldValue(), nextChange.getNewValue()),
                    Duration.ofMillis(10));
        bounds.subscribe(boundsChange -> {
            Bounds newBounds = boundsChange.getNewValue();
            Bounds oldBounds = boundsChange.getOldValue();
            if (newBounds.getWidth() != oldBounds.getWidth()) {
                if (newBounds.getMinX() != oldBounds.getMinX()) {
                    System.out.println("Resized from left");
                } else if (newBounds.getMaxX() != oldBounds.getMaxX()) {
                    System.out.println("Resized from right");
                }
            }
            if (newBounds.getHeight() != oldBounds.getHeight()) {
                if (newBounds.getMinY() != oldBounds.getMinY()) {
                    System.out.println("Resized from top");
                } else if (newBounds.getMaxY() != oldBounds.getMaxY()) {
                    System.out.println("Resized from bottom");
                }
            }
        });
        primaryStage.setScene(scene);
        primaryStage.show();
    }
    public static void main(String[] args) {
        launch(args);
    }
}

相关内容

  • 没有找到相关文章

最新更新