TornadoFx Undecorated 窗口从任务栏恢复时全屏显示

Dee*_*pan 6 javafx kotlin tornadofx

我一直在尝试 Tornadofx。尝试创建自定义标题栏,这是我目前正在尝试的代码

fun main(args: Array<String>) {
    launch<MyApp>(args)
}

class MyApp : App(Title::class) {
    override fun start(stage: Stage) {
        stage.initStyle(StageStyle.UNDECORATED)
        stage.minWidth = 600.0
        stage.minHeight = 450.0
        stage.isMaximized = false
        super.start(stage)
    }
}

class Title : View() {
    private var xOffset = 0.0
    private var yOffset = 0.0
    private var screenBounds: Rectangle2D = Screen.getPrimary().visualBounds
    private var originalBounds: Rectangle2D = Rectangle2D.EMPTY
    
    init {
        primaryStage.isMaximized = false
    }
    
    override val root = borderpane {
        onMousePressed = EventHandler { ev ->
            xOffset = primaryStage.x - ev.screenX
            yOffset = primaryStage.y - ev.screenY
        }
        
        onMouseDragged = EventHandler { ev ->
            primaryStage.x = xOffset + ev.screenX
            primaryStage.y = yOffset + ev.screenY
        }
        
        center = label("Forms")
        
        right = hbox {
            button("Mi") {
                action {
                    with(primaryStage) { isIconified = true }
                }
            }

            button("Ma") {
                action {
                    if (primaryStage.isMaximized) {
                        with(primaryStage) {
                            x = originalBounds.minX
                            y = originalBounds.minY
                            width = originalBounds.width
                            height = originalBounds.height
                            isMaximized = false
                        }
                        text = "Ma"
                    } else {
                        with(primaryStage) {
                            originalBounds = Rectangle2D(x, y, width, height)
                            x = screenBounds.minX
                            y = screenBounds.minY
                            width = screenBounds.width
                            height = screenBounds.height
                            isMaximized = true
                        }
                        text = "Re"
                    }
                }
            }

            button("X") {
                action {
                    app.stop()
                    println("exiting")
                    exitProcess(0)
                }
            }
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

以下工作没有问题

  • 关闭
  • 最大化,恢复
  • 恢复的窗口最小化,然后从任务栏打开

但是当最大化的窗口最小化到任务栏,然后从任务栏打开时,它会全屏显示(任务栏被隐藏)

我如何解决此行为,我的代码是否有任何部分错误、需要更改或需要包含任何内容?

我的配置是 Windows 10 64 位、Java 11.0.2、Kotlin 1.4.21、JavaFx 11.0.2、TornadoFx 1.7.20

Sai*_*dem 3

我认为这是 JavaFX 中的普遍问题(我的意思不是 TornadoFX 特有的问题)。

造成这种情况的根本原因是因为将stage的maximized属性设置为true。不确定 JavaFX 内部做了什么,但是当您从任务栏打开窗口时,如果最大值为 true,则它将以全屏模式呈现。

您可以通过两种方式解决此问题。

方法#1:

当从任务栏打开窗口时, iconfied 属性将关闭,如果最大化为 true,则将舞台尺寸再次设置为屏幕边界。

primaryStage.iconifiedProperty().addListener((obs,old,iconified)->{
    if(!iconified && primaryStage.isMaximized()){
        primaryStage.setWidth(screenBounds.getWidth());
        primaryStage.setHeight(screenBounds.getHeight());
    }
});
Run Code Online (Sandbox Code Playgroud)

方法#2:

不要依赖舞台的最大化属性。我相信您需要该属性来切换窗口尺寸。因此,请维护一个实例变量来处理该问题。

boolean maximized = false;
ma.setOnAction(e -> {
    if (maximized) {
        // Set stage to original bounds
        maximized = false;
        ma.setText("Ma");
    } else {
        // Set stage to screen bounds
        maximized = false;
        ma.setText("Re");
    }
});
Run Code Online (Sandbox Code Playgroud)

下面是这两种方法的完整工作演示。您可以根据您的其他要求决定走哪条路。

import javafx.application.Application;
import javafx.geometry.Insets;
import javafx.geometry.Rectangle2D;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.Label;
import javafx.scene.layout.BorderPane;
import javafx.scene.layout.HBox;
import javafx.stage.Screen;
import javafx.stage.Stage;
import javafx.stage.StageStyle;

public class UndecoratedWindowFullScreenDemo extends Application {
    private double xOffset = 0.0;
    private double yOffset = 0.0;
    private Rectangle2D screenBounds = Screen.getPrimary().getVisualBounds();
    private Rectangle2D originalBounds = Rectangle2D.EMPTY;
    private boolean maximized = false;

    @Override
    public void start(Stage primaryStage) throws Exception {
        BorderPane root = new BorderPane();
        root.setStyle("-fx-background-color:pink;");
        Scene scene = new Scene(root, 600, 450);
        primaryStage.setScene(scene);

        Label label = new Label("Forums");
        Button mi = new Button("Mi");
        Button ma = new Button("Ma");
        Button x = new Button("X");
        HBox pane = new HBox(mi, ma, x);
        pane.setPadding(new Insets(3));
        pane.setSpacing(5);
        root.setCenter(label);
        root.setRight(pane);

        primaryStage.initStyle(StageStyle.UNDECORATED);
        primaryStage.setMinWidth(600);
        primaryStage.setMinHeight(450);
        primaryStage.setMaximized(false);
        primaryStage.show();

        root.setOnMousePressed(e -> {
            xOffset = primaryStage.getX() - e.getScreenX();
            yOffset = primaryStage.getY() - e.getScreenY();
        });
        root.setOnMouseDragged(e -> {
            primaryStage.setX(xOffset + e.getScreenX());
            primaryStage.setY(yOffset + e.getScreenY());
        });
        mi.setOnAction(e -> primaryStage.setIconified(true));

        /* Use this approach if you want to go with the Stage maximized property */
        // approach1(primaryStage, ma);

        /* Use this approach if you want to avoid Stage maximized property and maintain a instance variable */
        approach2(primaryStage, ma);
    }

    private void approach1(Stage primaryStage, Button ma) {
        primaryStage.iconifiedProperty().addListener((obs, old, iconified) -> {
            if (!iconified && primaryStage.isMaximized()) {
                primaryStage.setWidth(screenBounds.getWidth());
                primaryStage.setHeight(screenBounds.getHeight());
            }
        });

        ma.setOnAction(e -> {
            if (primaryStage.isMaximized()) {
                primaryStage.setX(originalBounds.getMinX());
                primaryStage.setY(originalBounds.getMinY());
                primaryStage.setWidth(originalBounds.getWidth());
                primaryStage.setHeight(originalBounds.getHeight());
                primaryStage.setMaximized(false);
                ma.setText("Ma");
            } else {
                originalBounds = new Rectangle2D(primaryStage.getX(), primaryStage.getY(), primaryStage.getWidth(), primaryStage.getHeight());
                primaryStage.setX(screenBounds.getMinX());
                primaryStage.setY(screenBounds.getMinY());
                primaryStage.setWidth(screenBounds.getWidth());
                primaryStage.setHeight(screenBounds.getHeight());
                primaryStage.setMaximized(true);
                ma.setText("Re");
            }
        });
    }

    private void approach2(Stage primaryStage, Button ma) {
        ma.setOnAction(e -> {
            if (maximized) {
                primaryStage.setX(originalBounds.getMinX());
                primaryStage.setY(originalBounds.getMinY());
                primaryStage.setWidth(originalBounds.getWidth());
                primaryStage.setHeight(originalBounds.getHeight());
                maximized = false;
                ma.setText("Ma");
            } else {
                originalBounds = new Rectangle2D(primaryStage.getX(), primaryStage.getY(), primaryStage.getWidth(), primaryStage.getHeight());
                primaryStage.setX(screenBounds.getMinX());
                primaryStage.setY(screenBounds.getMinY());
                primaryStage.setWidth(screenBounds.getWidth());
                primaryStage.setHeight(screenBounds.getHeight());
                maximized = true;
                ma.setText("Re");
            }
        });
    }
}
Run Code Online (Sandbox Code Playgroud)