2016-06-15 43 views
1

阻止用户我有一个类似如下的应用程序:的JavaFX - 从不断变化的阶段,而无需使用MODAL

enter image description here

当用户点击卡片的甲板上,它开辟了一个新的阶段。

这个阶段可以通过以下两种方式之一关闭:

  • 右键单击阶段。

  • 点击舞台外(它有一个平衡处理器,当它失去焦点)。

然而,我有时需要用户从使用此窗口中的甲板选择一个或多个卡片。我不想让他关闭窗口,直到他选择了至少一张卡。这意味着我不得不使用MODAL阻止他进入下面的舞台(我的应用程序)。现在MODAL的问题是,即使我希望他能够做到,他现在也不会像以前那样通过点击舞台外的方式离开窗户。他现在只能通过右键点击离开。我可以添加一个按钮,但我真的不想。

我希望我解释得很好。你们会推荐我做什么?有没有办法阻止用户不用MODAL就可以回到前一阶段?舞台显示后我也无法更改Modality,因此无法使用。

谢谢!

回答

2

这个想法是使用弹出的StageonCloseRequestProperty属性。

当有外部请求关闭此窗口时调用。安装的事件处理程序可以通过使用收到的事件来阻止窗口关闭。

有了这个属性,你可以中断Stage闭幕如果(被选中的一个,以免卡在你的情况下)的条件不被在WindowEvent调用consume满足。

注:由于文档状态:它是唯一有效的,如果请求外部,所以如果你调用Stageclose方法,附加的监听器将不执行。作为一种解决方案而不是调用此方法,您可以手动激发WindowEvent.WINDOW_CLOSE_REQUEST事件。

例子:

public class PopUpApp extends Application { 

    Stage popupStage; 
    Stage primaryStage; 

    @Override 
    public void start(Stage stage) { 
     try { 
      BorderPane root = new BorderPane(); 
      Scene scene = new Scene(root, 400, 400); 
      primaryStage = stage; 

      initPopUpStage(); 

      // When the Pop-Up stage is showing, do not handle any action on the 
      // main GUI 
      root.disableProperty().bind(popupStage.showingProperty()); 

      Button b = new Button("Open deck"); 
      b.setOnAction(new EventHandler<ActionEvent>() { 

       @Override 
       public void handle(ActionEvent event) { 

        // Add some ToggleButtons to simulate the cards 
        VBox vbox = new VBox(); 
        vbox.setAlignment(Pos.CENTER); 

        List<ToggleButton> toggles = new ArrayList<ToggleButton>(); 

        for (int i = 0; i < 4; i++) { 
         ToggleButton tb = new ToggleButton("Card " + i + 1); 
         toggles.add(tb); 
        } 
        vbox.getChildren().addAll(toggles); 

        Scene sc = new Scene(vbox, 300, 300); 
        popupStage.setScene(sc); 

        // On close request check for the condition 
        popupStage.setOnCloseRequest(new EventHandler<WindowEvent>() { 

         @Override 
         public void handle(WindowEvent event) { 
          Boolean readytoClose = false; 
          for (ToggleButton toggle : toggles) { 
           if (toggle.isSelected()) { 
            readytoClose = true; 
            break; 
           } 
          } 

          // Consume the event a show a dialog 
          if (!readytoClose) { 
           event.consume(); 
           Alert alert = new Alert(AlertType.INFORMATION, 
             "At least one card has be to be selected!"); 
           alert.showAndWait(); 
          } 
         } 
        }); 

        popupStage.show(); 

       } 
      }); 

      root.setCenter(b); 

      primaryStage.setScene(scene); 
      primaryStage.show(); 
     } catch (Exception e) { 
      e.printStackTrace(); 
     } 
    } 

    private void initPopUpStage() { 
     popupStage = new Stage(); 
     popupStage.initOwner(primaryStage); 
     popupStage.initStyle(StageStyle.UNDECORATED); 
     // On focus loss, close the window 
     popupStage.focusedProperty().addListener(new ChangeListener<Boolean>() { 

      @Override 
      public void changed(ObservableValue<? extends Boolean> observable, Boolean oldValue, Boolean newValue) { 

       // Rather than popupStage.close(); fire the event manually 
       if (!newValue) 
        popupStage.fireEvent(new WindowEvent(popupStage, WindowEvent.WINDOW_CLOSE_REQUEST)); 
      } 
     }); 
    } 

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

更新:

将主Stage不可用我已经加入这一行:

root.disableProperty().bind(popupStage.showingProperty()); 

这将禁用根BorderPane而弹出式舞台正在显示。只要弹出窗口关闭,主窗口就会再次启用。

+0

非常感谢。我不知道我可以使用onCloseRequest来实现这种功能。尽管如此,这是一个巨大的问题。如果没有'Modality',尽管存在弹出阶段,用户仍然可以与应用程序的其余部分进行通信。他们可以点击甲板50次,并制作50个窗户。我目前的想法是在我的主要GUI类中有一个静态布尔变量,它说“是当前显示的窗口?”。如果该变量为真,则不允许在主要阶段激活任何事件处理程序。然而,这是一种痛苦。任何其他想法? – Hatefiend

+0

请在答案中查看我的更新。 – DVarga

+0

太棒了。最后一件事。我有六个独特的窗口将显示和隐藏像这样,我需要所有六个这样的绑定。现在,如果我调用'.bind()',它会覆盖前面的'bind',并且只有正确绑定的最后一个属性会影响禁用的属性。我怎样才能绑定多个? – Hatefiend