JavaFX 20 在同一屏幕上打开新窗口

问题描述 投票:0回答:1

我有一个小型 javafx 20 应用程序,它显示一个包含列表的主窗口(带 CSS 的 FXML)。双击任何行将打开一个新窗口来编辑该行。

问题是,如果主窗口位于辅助屏幕上,则编辑窗口将在主屏幕上打开,而不是在主窗口打开的辅助屏幕上打开。

我尝试使用 xProperty() 和 yProperty() 双精度值(另存为设置)来将第二个窗口定位为打开状态,但这仅适用于主窗口。编辑窗口似乎仅限于主屏幕的值。

有没有办法获取打开它的屏幕并使用该屏幕的 x 和 y 而不是主屏幕。

顺便说一句,NetBeans 在主屏幕中运行。这可能是一个线索...也许不是。

javafx netbeans fxml
1个回答
0
投票

嗯,事实证明这是一个比我预想的更有趣的挑战。

新窗口的位置有所不同

我看到的行为有所不同,具体取决于 👉🏼 您的代码是否重新定位新打开的窗口。

  • 如果您简单地执行
    new Stage
    stage.show()
    ,JavaFX会坚持在应用程序启动时首次使用的显示器/监视器上打开新窗口。用户可以将窗口移动到另一个显示器/监视器,但 JavaFX 坚持在第一个显示器上打开新窗口。诡异的。 JavaFX 似乎不知道另一个显示的存在,即使该显示包含当前窗口。
  • 如果您是程序员以编程方式在
    new Stage
    stage.show()
    之间移动舞台,
    行为会发生变化。现在 JavaFX 表现出我们期望的行为。新窗口出现在包含当前窗口的显示屏上。如果用户将该当前窗口拖动到另一个显示器,新窗口将出现在那里,而不是返回到原始显示器上。这种行为是有道理的......但是以编程方式重新定位舞台会触发这种明智的行为是多么奇怪,但默认情况下我们会得到奇怪的行为。

示例应用程序

该行为很容易演示。请参阅下面我的小示例应用程序。我希望有人可以验证我的代码,看看我是否做错了什么。

要使用该应用程序:

  1. 单击 打开另一个窗口 按钮,将当前窗口移动到另一个显示器/监视器,然后再次单击该按钮。请注意新窗口出现在原始显示屏上的奇怪行为。
  2. 在第二个显示屏上,选中重新定位每个新窗口复选框。然后单击打开另一个窗口按钮。请注意新窗口现在如何显示在第二个显示屏上,而不是原始显示屏上。正确的行为。
  3. 关闭重新定位每个新窗口复选框,然后看到奇怪的行为返回。

我猜测这种奇怪的行为是一个错误,但我无法真正辨别。

我在 MacBook Pro 16"(Apple Silicon、M1 Pro)上使用了 JavaFX 20.0.2 on Java 20.0.2,并通过 DisplayPort、macOS Ventura 连接了 BenQ 32 英寸 4K 显示器,从 IntelliJ IDE 启动。

package work.basil.example.exfxgatherinput;

import javafx.application.Application;
import javafx.event.ActionEvent;
import javafx.geometry.Insets;
import javafx.geometry.Pos;
import javafx.scene.Node;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.CheckBox;
import javafx.scene.control.Label;
import javafx.scene.layout.VBox;
import javafx.stage.Stage;
import javafx.stage.Window;

import java.time.Instant;
import java.util.concurrent.atomic.AtomicInteger;

public class OpenWindowApp extends Application
{
    private final AtomicInteger countWindows = new AtomicInteger ( 0 );

    @Override
    public void start ( Stage stage )
    {
        // Scene
        Scene scene = this.makeScene ( false );

        // Stage
        this.decorate ( stage );
        stage.setScene ( scene );
        stage.show ( );
    }

    private void decorate ( Stage stage )
    {
        stage.setTitle ( "Window # " + this.countWindows.incrementAndGet ( ) );

        stage.setWidth ( 380 );
        stage.setHeight ( 170 );
    }

    private Scene makeScene ( final boolean relocateNewWindow )
    {
        CheckBox relocateEachNewWindow = new CheckBox ( "Relocate each new window" );
        relocateEachNewWindow.setSelected ( relocateNewWindow );
        Label nowLabel = new Label ( "Window created at: " + Instant.now ( ).toString ( ) );
        Button newWindowButton = new Button ( );
        newWindowButton.setText ( "Open another window" );
        newWindowButton.setOnAction ( ( ActionEvent actionEvent ) ->
        {
            Stage stage = new Stage ( );
            this.decorate ( stage );
            stage.setScene ( this.makeScene ( relocateEachNewWindow.isSelected ( ) ) );
            if ( relocateEachNewWindow.isSelected ( ) )
            {
                this.relocateWindow ( actionEvent , stage );
            }
            stage.show ( );
        } );

        VBox vbox = new VBox ( relocateEachNewWindow , nowLabel , newWindowButton );
        vbox.setPadding ( new Insets ( 20 , 20 , 20 , 20 ) );
        vbox.setSpacing ( 12 );
        vbox.setAlignment ( Pos.CENTER );

        return new Scene ( vbox );
    }

    private void relocateWindow ( ActionEvent actionEvent , Stage stage )
    {
        Window currentWindow = ( ( Node ) actionEvent.getSource ( ) ).getScene ( ).getWindow ( );
        stage.setX ( currentWindow.getX ( ) + 50 );
        stage.setY ( currentWindow.getY ( ) + 50 );
    }

    public static void main ( String[] args )
    {
        launch ( );
    }
}
© www.soinside.com 2019 - 2024. All rights reserved.