代码之家  ›  专栏  ›  技术社区  ›  Waqar Ahmed

动态JavaFX视图的控制器类

  •  0
  • Waqar Ahmed  · 技术社区  · 5 年前

    我是新来的 JavaFX 春天 制作一个简单的桌面应用程序从 数据库 把它放在 表视图 . 我将所有代码放在一个类中,该类创建 意见 负载 表和句柄,用于添加新行和编辑表。但我不知道如何把这个班分成 控制器 意见 零件( 喜欢mvc模式 )。我的 看起来像这样:

    package com.waq;
    
    // some imports
    
    @Component
    public class PartsView{
    
        private TableView table;
        TextField desc;
        Label title;
        Button save;
        GridPane grid;
    
        @Autowired
        private PartService partService;
    
        public PartsView(){
            createTable();
            grid = new GridPane();
            save = new Button();
            save.setText("Save");
            save.setOnAction((ActionEvent e) -> {
                // Some logic
            }
        }
    
    
        private void loadData() {
            List<Part> parts = partService.findAll();
            if(parts.size() > 0) {
                ObservableList<Part> observableArrayList = FXCollections.observableArrayList(parts);
                table.setItems( observableArrayList);
            }
            else
                table.setPlaceholder(new Label("No data to show."));
        }
    
        private void saveData(){
            // save record.
        }
    
    
        private void createTable(){
            CustomTableColumn<Part,String> idColumn = new CustomTableColumn<Part,String>("id");
            idColumn.setPercentWidth(10);
            idColumn.setCellValueFactory(new PropertyValueFactory<Part,String>("id"));
    
            CustomTableColumn<Part,String> descCol = new CustomTableColumn<Part,String>("description");
            descCol.setPercentWidth(50);
            descCol.setCellValueFactory(new PropertyValueFactory<Part,String>("description"));
    
            table.getColumns().addAll(idColumn,descCol);
    
            grid.getChildren().add(table);
        }
    
    }
    

    我看到了其他的例子,但大多是在 小精灵 文件,然后使用 @ FXML 注释。但在我的例子中,我在类中创建视图对象。如果我在视图和控制器类中分离这个类,那么我将如何定义动作,让我们来保存按钮,以及如何访问控制器类中的表视图?

    任何帮助都将不胜感激。

    0 回复  |  直到 5 年前
        1
  •  0
  •   kozmo    5 年前

    如果创建自定义javafx Node 作为一个 Bean 你可以 @Autowired 它是控制器,但是你必须添加一个 结点 代表你的习俗 结点 .

    你有两种方法:

    1. extends 你的班级 结点 (或继承人) 结点 )(看例子)

    2. 下课回来 root-Node 其中包含其他节点

    例子:

    @Component
    @Scope("prototype") //If you want to reuse component `@Scope("prototype")`
    public class PartsView  extends GridPane{ 
      ...
      public void init(){
        getChildren().add(table);
      }
    
    }
    

    控制器应该看起来像:

    public class TestController implements Initializable  {
    
      @FXML //StackPane as example
      private StackPane stackPane; //injecting before constructor, when you load .fxml
      @Autowired
      private PartsView partsView; //injecting when you load spring-context
    
    
      @Override
      public void initialize(URL location, ResourceBundle resources) {
        // initialize fields marked @FXML annotation.
        // method initialize triggering after constructor
      }
    }
    

    鬃毛的问题是你必须添加你的自定义 结点 初始化前的上下文 Controller . 你可以写 Configuration 解决它:

    @Configuration
    @ComponentScan({
        "you.node.packege",
     })
    public class TestConfig{
    
    @Lazy                                  //depends on your case
    @Bean
    @Scope(BeanDefinition.SCOPE_PROTOTYPE) //depends on your case
    public ControlFx<TabPane, PlanningController> testViewFx() throws IOException {
        return loadView("/view/TestLayout.fxml");
    }
    
    
        private <V extends Node, C extends Initializable> ControlFx<V,C> loadView(String url) throws IOException {
            FXMLLoader loader = new FXMLLoader();
            loader.setLocation(getClass().getResource(url));
            return  new ViewFx<>(loader.load(), loader.getController());
        }
     }
    

    ControlFX类:

    public class ControlFx<N extends Node ,C extends Initializable>  {
        private final N view;
        private final C controller;
    
        public ControlFx(N view, C controller) {
            this.view = view;
            this.controller = controller;
        }
    
        public N getView() {
            return view;
        }
    
        public C getController() {
            return controller;
        }
    
    }
    

    我在视图和控制器类中分离这个类,然后我将如何定义动作,让我们来保存按钮,以及如何访问控制器类中的表视图?

    你可以写 facade -方法进入自定义类:

    public  void setOnActionSaveButton(EventHandler<ActionEvent> value){
        save.setOnAction((ActionEvent e) -> {
            // Some logic
        }
    }
    

    我用代码生成所有视图,没有任何fxml文件。在那种情况下,它将如何工作?

    使用 @Controller 注释(扩展 @Component @PostConstruct 注释或使用 @自动售货机 使用构造函数(或任何 init 方式:

    @Controller
    public class TestController {
    
       private StackPane stackPane;
       // @Autowired
       private PartsView  partsView;
    
       @Autowired
       public TestController (PartsView  partsView){
          ...
          stackPane.getChildren().add(partsView)
       }
    
       // @PostConstruct
       // private void beanPostConstruct() {
       //     stackPane.getChildren().add(partsView);
       // }
    }
    

    在第二和第三段代码中,您提到了加载fxml文件,但我没有。

    首先必须初始化spring上下文。我用过 AnnotationConfigApplicationContext :

    public abstract class AbstractJavaFxApplication extends Application {
    
        private static String[] savedArgs;
        protected AnnotationConfigApplicationContext context;
    
        @Override
        public void init() {
            context =  new AnnotationConfigApplicationContext(configurations());
            context.getAutowireCapableBeanFactory().autowireBean(this);
    
        }
    
        @Override
        public void stop() throws Exception {
            super.stop();
            context.close();
        }
    
        protected static void launchApp(Class<? extends AbstractJavaFxApplication> clazz, String[] args) {
            AbstractJavaFxApplication.savedArgs = args;
            Application.launch(clazz, savedArgs);
        }
    
        protected abstract Class<?>[] configurations();
    }
    

    IMPL:

    public class ReportApp extends AbstractJavaFxApplication {
    
        public final double PRIMARY_WINDOW_HEIGHT = 500;
        public final double PRIMARY_WINDOW_WIDTH = 500;
    
        @Value("${ui.title:JavaFX приложение}")
        private String windowTitle;
    
        @Autowired
        private RootLayoutController controller;
    
        @Override
        public void start(Stage stage) throws Exception {
            stage.setTitle(windowTitle);
            stage.setScene(
                    new Scene(
                            controller.getPane(),
                            PRIMARY_WINDOW_WIDTH,
                            PRIMARY_WINDOW_HEIGHT
                    )
            );
            stage.setResizable(true);
            stage.centerOnScreen();
            stage.show();
        }
    
        public static void main(String[] args) {
            launchApp(ReportApp.class, args);
        }
    
        @Override
        protected Class<?>[] configurations() {
            return new Class<?>[]{
                Config.class
            };
        }
    }
    

    配置:

    @Configuration
    @ComponentScan({"components", "controllers"})
    public class Config {
    
        @Bean
        ...
    }
    

    控制器:

    @Controller
    public class RootLayoutController {
    
        private StackPane stackPane;
        @Autowired
        private PartsView partsView;
    
        @PostConstruct
        private void init(){
            stackPane = new StackPane();
            stackPane.getChildren().add(partsView);
        }
    
        public Pane getPane(){
            return stackPane;
        }        
    }