简体   繁体   中英

Move a child stage when moving parent stage on Windows

I wonder if there is a way to move a JavaFX child Stage with its parent, when we move the parent stage on Windows. Indeed, on MacOS this seems to be the default behavior. As you can see in this video: https://imgur.com/a/r3qIklu , I can move the thumbnail scene independently and when I move the main window, the thumbnail (which is a child scene of the main window btw), remains "attached" to the parent and follows it.

However, on Windows, as you can see here: https://imgur.com/a/SPEkYJ2 , the result is not the same. When the parent stage is moved, the thumbnail stick to its current position. How can I reproduce the MacOS behaviour on Windows?

For reference, this is how my stages are initialized:

public void start(Stage primaryStage) {
    //App's main stage
    Parent root = FXMLLoader.load(getClass().getResource("../spaception.fxml"));
    Scene scene = new Scene(root, 1400, 700);
    primaryStage.setScene(scene);
    primaryStage.show();
    //...

    //Child stage (Thumbnail)
    Parent thumbnailRoot = FXMLLoader.load(getClass().getResource("../thumbnail.fxml"));
    Stage thumbnailStage = new Stage();
    thumbnailStage.initOwner(primaryStage);
    thumbnailStage.initStyle(StageStyle.UNDECORATED);
    thumbnailStage.setX(primaryStage.getX()+1100);
    thumbnailStage.setY(primaryStage.getY()+540);
    Scene scene = new Scene(thumbnailRoot, 250, 145);
    thumbnailStage.setScene(scene);
    thumbnailStage.show();
}

Place your root and your thumbnailRoot together in a regular Pane (which is the equivalent of a null layout in Swing).

To allow the user to move the thumbnailRoot, add mouse event handlers to it for pressing and dragging, and keep private fields that track thumbnailRoot's position and to keep track of the mouse dragging.

Simple example implementation:

import javafx.application.Application;
import javafx.geometry.Bounds;
import javafx.geometry.Insets;
import javafx.stage.Stage;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.Label;
import javafx.scene.control.Menu;
import javafx.scene.control.MenuItem;
import javafx.scene.control.MenuBar;
import javafx.scene.layout.Pane;
import javafx.scene.layout.BorderPane;
import javafx.scene.layout.VBox;
import javafx.scene.image.Image;
import javafx.scene.image.ImageView;
import javafx.scene.input.MouseButton;

public class ParentAndThumbnail
extends Application {
    private Bounds thumbnailBoundsOnPress;

    private double pressedX;
    private double pressedY;

    @Override
    public void start(Stage stage) {
        Label positionLabel = new Label("Current position: x y");

        VBox left =
            new VBox(6, new Button("+"), new Button("-"), new Button("C"));
        left.setFillWidth(true);
        left.setPadding(new Insets(6));
        left.getChildren().forEach(
            c -> ((Button) c).setMaxWidth(Double.MAX_VALUE));

        VBox right =
            new VBox(6, new Button("+"), new Button("-"), new Button("C"));
        right.setFillWidth(true);
        right.setPadding(new Insets(6));
        right.getChildren().forEach(
            c -> ((Button) c).setMaxWidth(Double.MAX_VALUE));

        MenuBar menuBar = new MenuBar(
            new Menu("File", null,
                new MenuItem("New"),
                new MenuItem("Open"),
                new MenuItem("Save"),
                new MenuItem("Exit")),
            new Menu("Edit", null,
                new MenuItem("Cut"),
                new MenuItem("Copy"),
                new MenuItem("Paste")));

        ImageView imagePane =
            new ImageView(new Image("parent-stage-background.png"));

        BorderPane root = new BorderPane(
            imagePane, menuBar, left, positionLabel, right);

        BorderPane thumbnailRoot = new BorderPane(
            new ImageView(new Image("thumbnail-background.png")));
        thumbnailRoot.setStyle(
            "-fx-border-width: 4px 30px 4px 30px; " +
            "-fx-border-color: black");

        thumbnailRoot.setOnMousePressed(e -> {
            if (e.getButton() == MouseButton.PRIMARY) {
                thumbnailBoundsOnPress = thumbnailRoot.getBoundsInParent();
                pressedX = e.getScreenX();
                pressedY = e.getScreenY();
            }
        });
        thumbnailRoot.setOnMouseDragged(e -> {
            if (e.getButton() == MouseButton.PRIMARY) {
                thumbnailRoot.setLayoutX(
                    thumbnailBoundsOnPress.getMinX()
                    + e.getScreenX() - pressedX);
                thumbnailRoot.setLayoutY(
                    thumbnailBoundsOnPress.getMinY()
                    + e.getScreenY() - pressedY);
            }
        });

        Pane overlay = new Pane();
        overlay.getChildren().addAll(root, thumbnailRoot);

        stage.setOnShown(e -> {
            thumbnailRoot.setLayoutX(root.getWidth() - 400);
            thumbnailRoot.setLayoutY(root.getHeight() - 200);
        });

        stage.setScene(new Scene(overlay));
        stage.setTitle("Spaception");
        stage.show();
    }

    public static class Main {
        public static void main(String[] args) {
            Application.launch(ParentAndThumbnail.class, args);
        }
    }
}

You can accomplish the same functionality in an.fxml file: just place the background and the thumbnail in a Pane. You can add mouse event handlers there too, if you wish.

Here is the image I used as parent-stage-background.png:

在此处输入图像描述

And here is the image I used as thumbnail-background.png:

在此处输入图像描述

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