将所有阶段置于前台

5
在我的应用程序中,我有几个独立的(非模态)舞台。
我希望实现以下行为:
  • 当主舞台被最小化时,所有其他舞台也应该被最小化
  • 当主舞台被取消最小化时,所有其他舞台也应该被取消最小化
  • 当选择任何一个舞台时,如果其他一些舞台不可见(例如隐藏在其他应用程序后面),它们应该被置于前台
前两个要求很容易实现(除非我错过了什么),可以采用下面的方法:
mainStage.iconifiedProperty().addListener((observable, oldValue, newValue) -> {
    if (newValue != null && newValue != oldValue) {
        for (Stage s : otherStages) { s.setIconified(newValue); }
    }
});

然而,我遇到了第三个问题。我尝试使用focusedProperty,但它不起作用(如果我在其中一个舞台中点击菜单,例如,因为它首先将其他舞台置于前面,它就失去了焦点,菜单也不会打开)...

//do this for each stage
stage.focusedProperty().addListener((observable, oldValue, newValue) -> {
    if (Boolean.TRUE.equals(newValue) && newValue != oldValue) {
        for (Stage s : otherStages) {
            s.setIconified(false);
            s.toFront();
        }
        //request the focus back, but that creates issues
        stage.requestFocus();
    }
});

有没有关于如何实现第三个要求的想法?
1个回答

7
解决方案 使用 stage.initOwner(parentStage) 方法。 示例应用 以下是一个快速测试应用,它将所有创建的舞台的所有者初始化为主应用程序舞台。
这个测试应用看起来符合你所有的要求(在 Windows 7、JavaFX 8b122 上进行了测试)。
import javafx.application.Application;
import javafx.scene.*;
import javafx.scene.paint.Color;
import javafx.scene.shape.Rectangle;
import javafx.stage.Stage;
import javafx.stage.StageStyle;

public class LotsaStages extends Application {
    private static final Color[] STAGE_COLORS = { 
        Color.RED, Color.GREEN, Color.BLUE, Color.YELLOW 
    };
    private static final double  STAGE_OFFSET = 50;

    @Override
    public void start(Stage primaryStage) throws Exception {
        addContent(primaryStage, Color.LIGHTBLUE);
        primaryStage.show();

        double offset = STAGE_OFFSET;
        for (Color color: STAGE_COLORS) {
            Stage child = new Stage();
            child.initOwner(primaryStage);
            child.initStyle(StageStyle.UTILITY);

            child.setX(primaryStage.getX() + offset);
            child.setY(primaryStage.getY() + offset);

            addContent(child, color);

            child.show();

            offset += STAGE_OFFSET;
        }
    }

    private void addContent(Stage child, Color color) {
        child.setScene(
            new Scene(
                new Group(
                    new Rectangle(150, 70, color)
                )
            )
        );
    }

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

测试应用程序很简单,我没有尝试复制您基于菜单的问题,因此我不确定它是否适用于基于菜单的处理或您可能拥有的其他要求。

其他问题

所以initOwner基本上将子窗口与主窗口关联起来了吗?

是的,MSDN解释了Windows上窗口占有关系的工作原理。在其他平台上行为可能略有不同(这就是为什么JavaFX文档在此问题上故意含糊不清的原因),但我认为大部分原则都是相同的,并且在OS X和Linux上以类似的方式工作。

来自MSDN:

为了允许您创建子窗口与父窗口之间的关系,Window支持所有权概念。当将一个窗口的Owner属性(即拥有窗口)设置为对另一个窗口(即所有者窗口)的引用时,将建立所有权。

建立此关系后,会出现以下行为:

  • 如果所有者窗口被最小化,则其所有拥有的窗口也会被最小化。
  • 如果拥有的窗口被最小化,则其所有者不会被最小化。
  • 如果所有者窗口被最大化,则所有者窗口和其拥有的窗口都将被恢复。
  • 所有者窗口永远不能覆盖所有拥有的窗口。
  • 未使用ShowDialog打开的拥有窗口不是模态的。用户仍然可以与所有者窗口交互。
  • 如果关闭所有者窗口,则其拥有的窗口也会关闭。
  • 如果使用Show从其所有者窗口中打开拥有的窗口,并且关闭所有者窗口,则不会引发拥有的窗口的Closing事件。

当您通过调用ShowDialog打开子窗口时,还应设置子窗口的Owner属性。如果不这样做,那么您的用户将无法通过按任务栏按钮来恢复子窗口和父窗口。相反,按下任务栏按钮将产生一个窗口列表,包括子窗口和父窗口,供用户选择;只有所选窗口会被恢复。


它能够处理像child = new Stage(UNDECORATED); child.initModality(Modality.NONE);这样的子窗口吗?

可以,它可以。


一个舞台可以选择拥有一个所有者窗口。当一个窗口是舞台的所有者时,它被称为该舞台的父级。当一个父窗口关闭时,它的所有子窗口都会关闭。对于一个被最小化的父窗口,同样适用相同的链式行为。一个舞台将始终位于其父窗口的顶部。所有者必须在舞台可见之前初始化。 - Linuslabo

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接