2015-04-25 70 views
1

所以我正在運行一個小測試應用程序,看看是否可能,然後將其移動到我的主項目。主要思想是對話框從屏幕的頂部到中心,並等待用戶的響應。如果他們點擊否,程序將終止。如果他們單擊是,則對話框從中心到頂部屏幕,並且不在用戶的視線範圍內。是否可以在javafx的對話框中使用路徑轉換?

package test; 

import java.util.Optional; 
import javafx.animation.PathTransition; 
import javafx.application.Application; 
import javafx.fxml.FXMLLoader; 
import javafx.scene.Scene; 
import javafx.scene.control.Alert; 
import javafx.scene.control.Alert.AlertType; 
import javafx.scene.control.ButtonType; 
import javafx.scene.layout.VBox; 
import javafx.scene.shape.MoveTo; 
import javafx.scene.shape.Path; 
import javafx.scene.shape.VLineTo; 
import javafx.stage.Stage; 
import javafx.util.Duration; 

public class Test extends Application 
{ 

    @Override 
    public void start(Stage stage) throws Exception 
    { 
     VBox root = FXMLLoader.load(getClass().getResource("FXMLDocument.fxml")); 

     Alert alert = new Alert(AlertType.CONFIRMATION); 
     alert.setTitle("Confirmation Dialog"); 
     alert.setHeaderText("Look, a Confirmation Dialog"); 
     alert.setContentText("Are you ok with this?"); 

     Path path = new Path(); 
     path.getElements().add(new MoveTo(300, -25)); 
     path.getElements().add(new VLineTo(200)); 
     PathTransition pathTransition = new PathTransition(); 
     pathTransition.setDuration(Duration.millis(1500)); 
     pathTransition.setPath(path); 
     pathTransition.setNode(alert); // This is where the problem lies. 
     pathTransition.setCycleCount(1); 
     pathTransition.play(); 

     Scene scene = new Scene(root, 640, 480); 

     stage.setScene(scene); 
     stage.show(); 

     Optional<ButtonType> result = alert.showAndWait(); 

     if (result.get() == ButtonType.OK) 
     { 
      Path path2 = new Path(); 
      path2.getElements().add(new MoveTo(300, 200)); 
      path2.getElements().add(new VLineTo(-25)); 
      PathTransition pathTransition2 = new PathTransition(); 
      pathTransition.setDuration(Duration.millis(1500)); 
      pathTransition.setPath(path); 
      pathTransition.setNode(alert); 
      pathTransition.setCycleCount(1); 
      pathTransition.play(); 
     } 
     else 
     { 
      stage.close(); 
     } 
    } 

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

} 

回答

1

有,你可以通過它的yProperty()的方式移動的警告對話框中,一種方式。我們將使用時間軸來設置此屬性,而不是路徑轉換。但由於這是隻讀屬性,我們不必在轉換中使用DoubleProperty,而應使用Alert.setY()

問題的第一部分在對話框中滑動很容易。其次,滑出更復雜,因爲一旦單擊按鈕,對話框立即關閉。

解決方案1.在

只需滑動我們需要對話的尺寸和位置,爲此,我們需要展示出來。這意味着它會顯示,並立即移動到屏幕的頂部。

所以我會更換alert.showAndWait()alert.show()

@Override 
public void start(Stage primaryStage) { 

    Button btn = new Button(); 
    btn.setText("Show Sliding In Alert Dialog"); 
    btn.setOnAction(event -> { 
     Alert alert = new Alert(AlertType.CONFIRMATION); 
     alert.setTitle("Confirmation Dialog"); 
     alert.setHeaderText("Look, a Confirmation Dialog"); 
     alert.setContentText("Are you ok with this?"); 

     ButtonBar buttonBar=(ButtonBar)alert.getDialogPane().lookup(".button-bar"); 
     buttonBar.setDisable(true); 

     alert.initModality(Modality.APPLICATION_MODAL); 
     alert.show(); 
     // now we can retrive alert bounds: 
     double yIni=-alert.getHeight(); 
     double yEnd=alert.getY(); 
     // and move alert to the top of the screen 
     alert.setY(yIni); 

     final DoubleProperty yProperty = new SimpleDoubleProperty(); 
     yProperty.addListener((ob,n,n1)->alert.setY(n1.doubleValue())); 

     Timeline timeIn = new Timeline(); 
     timeIn.getKeyFrames().add(
      new KeyFrame(Duration.seconds(1.5), 
       e->buttonBar.setDisable(false), 
       new KeyValue(yProperty, yEnd,Interpolator.EASE_BOTH))); 
     timeIn.play(); 

     alert.resultProperty().addListener((ob,r,r1)->{ 
      if (r1 == ButtonType.OK){ 
       // alert is closed and hidden in its final position 
      } 
      else{ 
       primaryStage.close(); 
      } 
     }); 

    }); 

    StackPane root = new StackPane(); 
    root.getChildren().add(btn); 

    Scene scene = new Scene(root, 300, 250); 

    primaryStage.setTitle("Hello World!"); 
    primaryStage.setScene(scene); 
    primaryStage.show(); 
} 

yProperty()監聽器允許我們設置在過渡期間內插所有的不同的位置中的位置的對話框。

溶液2滑入和滑出

這有點髒溶液,因爲使用第二Alert對話框包括,給予一次的按鈕被點擊原來的關閉。我們將在第一個對話框後面添加第二個對話框,並在第一個對話框關閉後使用它創建滑出效果。

您會注意到的唯一副作用是在顯示第二個並將第一個放在第一個之上的快速閃爍。

@Override 
public void start(Stage primaryStage) { 
    Button btn = new Button(); 
    btn.setText("Show Sliding In Alert Dialog"); 
    btn.setOnAction(event -> { 
     Alert alert = new Alert(AlertType.CONFIRMATION); 
     alert.setTitle("Confirmation Dialog"); 
     alert.setHeaderText("Look, a Confirmation Dialog"); 
     alert.setContentText("Are you ok with this?"); 

     Alert alertOut = new Alert(AlertType.CONFIRMATION); 
     alertOut.setTitle("Confirmation Dialog"); 
     alertOut.setHeaderText("Look, a Confirmation Dialog"); 
     alertOut.setContentText("Are you ok with this?"); 
     alertOut.initModality(Modality.NONE); 
     ((Stage)alertOut.getDialogPane().getScene().getWindow()).setOpacity(0); 

     ButtonBar buttonBar=(ButtonBar)alert.getDialogPane().lookup(".button-bar"); 
     buttonBar.setDisable(true); 
     alert.initModality(Modality.APPLICATION_MODAL); 
     alert.show();    
     // now we can retrive alert bounds: 
     double yIni=-alert.getHeight(); 
     double yEnd=alert.getY(); 
     // and move alert to the top of the screen 
     alert.setY(yIni); 

     final DoubleProperty yProperty = new SimpleDoubleProperty(); 
     yProperty.addListener((ob,n,n1)->alert.setY(n1.doubleValue())); 
     Timeline timeIn = new Timeline(); 
     timeIn.getKeyFrames().add(
      new KeyFrame(Duration.seconds(1.5), 
       e->{ 
        buttonBar.setDisable(false); 
        // show second dialog 
        alertOut.show(); 
        // move to front the first one 
        ((Stage)alert.getDialogPane().getScene(). 
         getWindow()).toFront(); 
       }, new KeyValue(yProperty, yEnd,Interpolator.EASE_BOTH))); 
     timeIn.play(); 

     alert.resultProperty().addListener((ob,r,r1)->{ 
      if (r1 == ButtonType.OK){ 
       // show second dialog 
       ((Stage)alertOut.getDialogPane().getScene().getWindow()).setOpacity(1); 
       ButtonBar buttonBarOut=(ButtonBar)alertOut.getDialogPane().lookup(".button-bar"); 
       buttonBarOut.setDisable(true); 
       final DoubleProperty yPropertyOut = new SimpleDoubleProperty(yEnd); 
       yPropertyOut.addListener((ov,n,n1)->alertOut.setY(n1.doubleValue()));        
       // Create slide out transition 
       Timeline timeOut = new Timeline(); 
       timeOut.getKeyFrames().add(
        new KeyFrame(Duration.seconds(1.5), 
         e->alertOut.close(), 
         new KeyValue(yPropertyOut, yIni,Interpolator.EASE_BOTH))); 
       timeOut.play(); 
      } 
      else{ 
       alertOut.close(); 
       primaryStage.close(); 
      } 
     }); 

    }); 

    StackPane root = new StackPane(); 
    root.getChildren().add(btn); 

    Scene scene = new Scene(root, 300, 250); 

    primaryStage.setTitle("Hello World!"); 
    primaryStage.setScene(scene); 
    primaryStage.show(); 
} 

編輯

解決方案2.改進和拉出

我發現使用一個單一的對話框,並提供了在滑動過的方式。

它只需將點擊動作置於所選按鈕上,消耗事件,在此處添加滑出過渡,並隱藏完成對話框。

@Override 
public void start(Stage primaryStage) { 
    Button btn = new Button(); 
    btn.setText("Show Sliding In Alert Dialog"); 
    btn.setOnAction(event -> { 
     Alert alert = new Alert(AlertType.CONFIRMATION); 
     alert.setTitle("Confirmation Dialog"); 
     alert.setHeaderText("Look, a Confirmation Dialog"); 
     alert.setContentText("Are you ok with this?"); 

     ButtonBar buttonBar=(ButtonBar)alert.getDialogPane().lookup(".button-bar"); 
     buttonBar.setDisable(true); 
     alert.initModality(Modality.APPLICATION_MODAL); 
     alert.show();    
     // now we can retrive alert bounds: 
     double yIni=-alert.getHeight(); 
     double yEnd=alert.getY(); 
     // and move alert to the top of the screen 
     alert.setY(yIni); 

     buttonBar.getButtons().stream().filter(b->((Button)b).isDefaultButton()).findFirst() 
      .ifPresent(b->((Button)b).addEventFilter(EventType.ROOT, 
       e->{ 
        if(e.getEventType().equals(ActionEvent.ACTION)){ 
         e.consume(); 
         final DoubleProperty yPropertyOut = new SimpleDoubleProperty(yEnd); 
         yPropertyOut.addListener((ov,n,n1)->alert.setY(n1.doubleValue()));    
         Timeline timeOut = new Timeline(); 
         timeOut.getKeyFrames().add(new KeyFrame(Duration.seconds(1.5), t->alert.close(), 
           new KeyValue(yPropertyOut, yIni,Interpolator.EASE_BOTH))); 
         timeOut.play(); 
        } 
       })); 

     final DoubleProperty yProperty = new SimpleDoubleProperty(); 
     yProperty.addListener((ob,n,n1)->alert.setY(n1.doubleValue())); 
     Timeline timeIn = new Timeline(); 
     timeIn.getKeyFrames().add(new KeyFrame(Duration.seconds(1.5), e->{ 
      buttonBar.setDisable(false); 
     },new KeyValue(yProperty, yEnd,Interpolator.EASE_BOTH))); 
     timeIn.play(); 
    }); 

    StackPane root = new StackPane(); 
    root.getChildren().add(btn); 

    Scene scene = new Scene(root, 300, 250); 

    primaryStage.setTitle("Hello World!"); 
    primaryStage.setScene(scene); 
    primaryStage.show(); 
} 
+0

酷,我可能會使用第一個解決方案,並嘗試調整,使該按鈕只是來和自動退出。 –

+0

謝謝,我也會選擇第一個... –

+0

你能簡單介紹一下Interpolator.EASE_BOTH的功能嗎? –

相關問題