将所有阶段都带到前面

时间:2014-01-06 19:24:34

标签: java javafx javafx-8

在我的申请中,我有几个独立(非模态)阶段。

我想要以下行为:

  • 当主舞台最小化时,所有其他舞台应最小化
  • 当主舞台未被最小化时,所有其他舞台应该是未最小化的
  • 当选择任何阶段时,如果某些其他阶段不可见(例如隐藏在其他应用程序后面),则应将它们带到前面

前两个要求很简单(除非我遗漏了一些东西),例如:

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 个答案:

答案 0 :(得分:6)

<强>解决方案

使用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 explains how window ownage works on Windows。在其他平台上行为可能略有不同(这就是为什么JavaFX Javadoc在此问题上是故意模糊的),但我认为大多数原则是相同的,它应该适用于OS X和Linux是类似的方式。

来自MSDN:

  

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

     

一旦建立了这种关系,就会出现以下行为:

     
      
  • 如果所有者窗口最小化,其所有拥有的窗口也会最小化。
  •   
  • 如果拥有的窗口最小化,则其所有者不会最小化。
  •   
  • 如果所有者窗口最大化,则还原所有者窗口及其拥有的窗口。
  •   
  • 所有者窗口永远不能涵盖拥有的窗口。
  •   
  • 使用ShowDialog未打开的自有窗口不是模态的。用户仍然可以与所有者窗口进行交互。
  •   
  • 如果您关闭所有者窗口,其拥有的窗口也会关闭。
  •   
  • 如果所有者窗口由其所有者窗口使用Show打开,并且所有者窗口关闭,则不会引发拥有窗口的Closing事件。
  •   
     

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


  

这可以与child = new Stage(UNDECORATED); child.initModality(Modality.NONE);等儿童一起使用吗?

是的,确实如此。