JavaFx之不通過全局靜態變量進行窗體通信


百度了n多窗體通信,,,總是通過定義全局靜態變量進行傳值通信。。我個人不喜歡一個controller里寫滿所有的布局(這樣顯得臃腫,但是組件傳值方便)。有沒有另外的辦法進行模塊化並且可以傳值呢。。

肯定是有的。。。

1.定義一個泛型類接收Controller對象與Stage對象

 

 1 public class StageAndController<C, S> {  2     private C controller;  3     private S stage;  4 
 5     public StageAndController(C controller, S stage) {  6         this.controller = controller;  7         this.stage = stage;  8  }  9     public StageAndController(C controller) { 10         this.controller = controller; 11  } 12 
13     public C getController() { 14         return controller; 15  } 16 
17     public void setController(C controller) { 18         this.controller = controller; 19  } 20 
21     public S getStage() { 22         return stage; 23  } 24 
25     public void setStage(S stage) { 26         this.stage = stage; 27  } 28 }

 

這里之所以返回兩個對象,,首先每個controller都對應一個打開的布局窗體,controller用來傳值、賦值、初始化操作,stage本身需要調用show()才顯示,,所以定義此類

 

2.封裝 打開一個窗體或者動態加載一個Node

 1 public static StageAndController addMenu(final Pane pane, final String fxmlName, Object controller) {  2         URL location = AddOperation.class.getResource("/fxml/" + fxmlName);  3         FXMLLoader fxmlLoader = new FXMLLoader();  4  fxmlLoader.setLocation(location);  5         fxmlLoader.setBuilderFactory(new JavaFXBuilderFactory());  6         try {  7             Node node = fxmlLoader.load();//返回Node對象 Node是布局頂級父類,再之上就是Object,所有此處可以加載一個布局添加到父級中  8  pane.getChildren().add(node);//Node添加到父級布局  9             controller = fxmlLoader.getController();//獲取加載布局的Contrller對象 10         } catch (IOException e) { 11  e.printStackTrace(); 12  } 13         return new StageAndController(controller);//返回controller實例 14     }
//pane->需要添加node的父級Pane及Pane子類對象  fxmlName-->自定義的布局文件   Object-->需要實例化的Controller

這里我的用法是動態增加一排菜單欄,使用了到了controller傳值作用,用法如下:

StageAndController controller = AddOperation.addMenu(operation, "read_item.fxml", ReadCardController.class); readCardController = (ReadCardController) controller.getController();

向父級窗體暴露了一個Controller實例對象,就可以進行父窗體向子組件傳值,初始化。

-------------------------------------------------------------------------------------------------------

 1  public static StageAndController newDialog(String fxmlName, String title, Object controller) {  2         URL location = OpenDialog.class.getResource("/fxml/" + fxmlName);  3         FXMLLoader fxmlLoader = new FXMLLoader();  4  fxmlLoader.setLocation(location);  5         fxmlLoader.setBuilderFactory(new JavaFXBuilderFactory());  6         Stage stage = new Stage();  7         try {  8             Pane dialogPane = fxmlLoader.load();  9             stage.setScene(new Scene(dialogPane)); 10  stage.initModality(Modality.APPLICATION_MODAL); 11  stage.initStyle(StageStyle.DECORATED); 12             stage.setResizable(false); 13             if (title != null) { 14  stage.setTitle(title); 15  } 16             controller = fxmlLoader.getController(); 17 
18         } catch (IOException e) { 19  e.printStackTrace(); 20  } 21         return new StageAndController(controller, stage);

此處同理,加載的是一個窗體布局,同時設置模態化(本身未關閉,父級窗體不可點擊)、動態標題,,,,,返回一個Controller與Stage對象,,,用法如下:

 StageAndController stageAndController = OpenDialog.newDialog("connectDevice.fxml", "連接", ConnectDevice.class);
        ConnectDevice controller = (ConnectDevice) stageAndController.getController(); Stage stage = (Stage) stageAndController.getStage();
        controller.str= str; controller.init(); stage.show();

窗體顯示之前父窗體向子窗體傳值或者做一些初始化。 這樣模塊化布局傳值也變得簡單好維護。

-------------------------------------------------------------------------------------------------------

嫌棄自帶窗體風格太丑,,可以往下看。。

自定義Stage窗體布局(State設置透明時):

public static StageAndController customDialog(String fxmlName, Object controller, Pane pane, String css) { URL location = OpenDialog.class.getResource("/fxml/" + fxmlName); FXMLLoader fxmlLoader = new FXMLLoader(); fxmlLoader.setLocation(location); fxmlLoader.setBuilderFactory(new JavaFXBuilderFactory()); Stage stage = new Stage(); try { pane = fxmlLoader.load(); Background background = new Background(new BackgroundFill(Paint.valueOf("#EFEFEF"), new CornerRadii(15), new Insets(0))); pane.setBackground(background); pane.setBorder(new Border(new BorderStroke(Color.valueOf("#0096C9"), BorderStrokeStyle.SOLID, new CornerRadii(15), new BorderWidths(2)))); Scene scene = new Scene(pane); if (css != null) { scene.getStylesheets().add(OpenDialog.class.getResource("/css/" + css).toExternalForm()); } scene.setFill(Paint.valueOf("#FFFFFF00"));//設置場景透明
 stage.initModality(Modality.APPLICATION_MODAL); stage.initStyle(StageStyle.TRANSPARENT); stage.setResizable(false); stage.setScene(scene); controller = fxmlLoader.getController(); } catch (IOException e) { e.printStackTrace(); } return new StageAndController(controller, stage); }

用法差不多,加了一個自定義加載css樣式,可以按需更改,,不過自定義時,,窗體頭部拖動就不可用,下面貼出解決方案:

 1 public class DragListener implements EventHandler<MouseEvent> {  2 
 3     private double xOffset = 0;  4     private double yOffset = 0;  5     private final Stage stage;  6 
 7     public DragListener(Stage stage) {  8         this.stage = stage;  9  } 10 
11  @Override 12     public void handle(MouseEvent event) { 13  event.consume(); 14         if (event.getEventType() == MouseEvent.MOUSE_PRESSED) { 15             xOffset = event.getSceneX(); 16             yOffset = event.getSceneY(); 17         } else if (event.getEventType() == MouseEvent.MOUSE_DRAGGED) { 18             stage.setX(event.getScreenX() - xOffset); 19             if(event.getScreenY() - yOffset < 0) { 20                 stage.setY(0); 21             }else { 22                 stage.setY(event.getScreenY() - yOffset); 23  } 24  } 25  } 26 
27     public void enableDrag(Node node) { 28         node.setOnMousePressed(this); 29         node.setOnMouseDragged(this); 30  } 31 }

用法如下:

1   StageAndController stageAndController = OpenDialog.customDialog("connectDevice_cus.fxml",ConnectDevice.class,new Pane(),null); 2         ConnectDevice controller = (ConnectDevice) stageAndController.getController(); 3         Stage stage = (Stage) stageAndController.getStage(); 4         new DragListener(stage).enableDrag(controller.title);//自定義窗口時設置拖動監聽 此處controller.title是我自定義窗體標題欄的HBox對象
5         controller.stage = stage; 6  controller.init(); 7         stage.show();

這樣就可以愉快的使用自定義彈窗了。。。。

-------------------------------------------------------------------------------------------------------

不喜勿噴!!!! 歡迎進群學習交流(927465926)


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM