2016-06-15 41 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