百度了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)