百度了n多窗体通信,,,总是通过定义全局静态变量进行传值通信。。我个人不喜欢一个controller里写满所有的布局(这样显得臃肿,但是组件传值方便)。有没有另外的办法进行模块化并且可以传值呢。。

肯定是有的。。。

1.定义一个泛型类接收Controller对象与Stage对象

 

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

 

这里之所以返回两个对象,,首先每个controller都对应一个打开的布局窗体,controller用来传值、赋值、初始化操作,stage本身需要调用show()才显示,,所以定义此类

 

2.封装 打开一个窗体或者动态加载一个Node

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

这里我的用法是动态增加一排菜单栏,使用了到了controller传值作用,用法如下:

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

向父级窗体暴露了一个Controller实例对象,就可以进行父窗体向子组件传值,初始化。

 ———————————————————————————————————————————————————————————————————————–

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

此处同理,加载的是一个窗体布局,同时设置模态化(本身未关闭,父级窗体不可点击)、动态标题,,,,,返回一个Controller与Stage对象,,,用法如下:

  1. StageAndController stageAndController = OpenDialog.newDialog("connectDevice.fxml", "连接", ConnectDevice.class);
  2. ConnectDevice controller = (ConnectDevice) stageAndController.getController();
  3. Stage stage = (Stage) stageAndController.getStage();
  4. controller.str= str;
  5. controller.init();
  6. stage.show();

窗体显示之前父窗体向子窗体传值或者做一些初始化。 这样模块化布局传值也变得简单好维护。

—————————————————————————————————————————————————————————–

嫌弃自带窗体风格太丑,,可以往下看。。

自定义Stage窗体布局(State设置透明时):

  1. public static StageAndController customDialog(String fxmlName, Object controller, Pane pane, String css) {
  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 = fxmlLoader.load();
  9. Background background = new Background(new BackgroundFill(Paint.valueOf("#EFEFEF"), new CornerRadii(15), new Insets(0)));
  10. pane.setBackground(background);
  11. pane.setBorder(new Border(new BorderStroke(Color.valueOf("#0096C9"), BorderStrokeStyle.SOLID, new CornerRadii(15), new BorderWidths(2))));
  12. Scene scene = new Scene(pane);
  13. if (css != null) {
  14. scene.getStylesheets().add(OpenDialog.class.getResource("/css/" + css).toExternalForm());
  15. }
  16. scene.setFill(Paint.valueOf("#FFFFFF00"));//设置场景透明
  17. stage.initModality(Modality.APPLICATION_MODAL);
  18. stage.initStyle(StageStyle.TRANSPARENT);
  19. stage.setResizable(false);
  20. stage.setScene(scene);
  21. controller = fxmlLoader.getController();
  22. } catch (IOException e) {
  23. e.printStackTrace();
  24. }
  25. return new StageAndController(controller, stage);
  26. }

用法差不多,加了一个自定义加载css样式,可以按需更改,,不过自定义时,,窗体头部拖动就不可用,下面贴出解决方案:

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

用法如下:

  1. 1 StageAndController stageAndController = OpenDialog.customDialog("connectDevice_cus.fxml",ConnectDevice.class,new Pane(),null);
  2. 2 ConnectDevice controller = (ConnectDevice) stageAndController.getController();
  3. 3 Stage stage = (Stage) stageAndController.getStage();
  4. 4 new DragListener(stage).enableDrag(controller.title);//自定义窗口时设置拖动监听 此处controller.title是我自定义窗体标题栏的HBox对象
  5. 5 controller.stage = stage;
  6. 6 controller.init();
  7. 7 stage.show();

这样就可以愉快的使用自定义弹窗了。。。。

————————————————————————————————————–

  1. 不喜勿喷!!!! 欢迎进群学习交流(927465926

版权声明:本文为wtzl原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://www.cnblogs.com/wtzl/p/10610038.html