【问题标题】:MVC javafx Application, when to inject modelMVC javafx 应用程序,何时注入模型
【发布时间】:2017-07-26 19:10:10
【问题描述】:

我有一个应用程序,我试图保持 mvc 规则。我有一个模型

public class CarTableView {
SimpleIntegerProperty id = new SimpleIntegerProperty();
SimpleStringProperty brand = new SimpleStringProperty();
SimpleStringProperty engine = new SimpleStringProperty();
SimpleBooleanProperty navi = new SimpleBooleanProperty();
SimpleBooleanProperty available = new SimpleBooleanProperty();
SimpleDoubleProperty liters = new SimpleDoubleProperty();
SimpleIntegerProperty power = new SimpleIntegerProperty();

ObservableList<CarTableView> observableList = FXCollections.observableArrayList();
public CarTableView()
{

}
public CarTableView(int id,String brand,String engine,Boolean navi,Boolean available,double liters,int power)
{
    this.id.set(id);
    this.brand.set(brand);
    this.engine.set(engine);
    this.navi.set(navi);
    this.available.set(available);
    this.liters.set(liters);
    this.power.set(power);
}

我需要在我的两个控制器中使用它才能获得对 ObservableList 的引用。这就是我的问题所在。在哪里创建模型?我需要在调用 initialize() 方法之前创建他

public class MainController {

private CarTableView model = new CarTableView();
@FXML
private Button addVehicleButton;

@FXML
private Button showClientDatabaseButton;

@FXML
public void initialize()
{

(...)
    model.getObservableList().add(new CarTableView(213,"FIAT","1.9 JTD",true,true,32.4,132)); // HERE I use model (it's fine here because its created in this class)
    tableView.setItems(model.getObservableList());

@FXML
public void addNewVehicleButtonClicked() throws IOException
{
    FXMLLoader loader = new FXMLLoader(getClass().getResource("/fxml/AddNewCar.fxml"));
    Stage stage = new Stage();
    Scene scene = new Scene((Pane)loader.load());
    stage.setScene(scene);
    stage.show();
    AddNewCarController addNewCarController = loader.getController();
    addNewCarController.initData(model); // HERE i try to initialize model in second controller

}

但我在另一个控制器的 initialize() 方法中也需要他

public class AddNewCarController {

private ObservableList<String> choiceBoxList = FXCollections.observableArrayList("YES","NO");
@FXML
public void initialize()
{
    autoIncrementChekBox.setSelected(true);
    if(autoIncrementChekBox.isSelected())
    {
        idTextField.setText(Integer.toString((model.getObservableList().size()+1))); // HERE I NEED HIM TOO!! But it is null... he havent been load yet!
        idTextField.setDisable(true);
    }
    comboBox.setItems(choiceBoxList);
    comboBox.setValue("YES");
}

在这种情况下,即使我将在第二个控制器中传递数据抛出函数 initModel()。我应该在哪里创建模型并传递给两个控制器? 我还将添加我的 Main() 文件以清除情况

public class Main extends Application {

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

}

@Override
public void start(Stage stage) throws Exception {
    stage.setTitle("Managment System");
    FXMLLoader loader = new FXMLLoader(getClass().getResource("/fxml/Main.fxml"));
    Scene scene = new Scene((Pane)loader.load(),1800,900);
    MainController mainController = loader.getController();
    stage.setScene(scene);
    stage.show();

}

}

【问题讨论】:

    标签: model-view-controller javafx javafx-8


    【解决方案1】:

    您可以创建控制器,以便将模型传递给构造函数:

    public class MainController {
    
        private final CarTableView model ;
    
        public MainController(CarTableView model) {
            this.model = model ;
        }
    
        // existing code ...
    
    }
    

    要使用此版本的控制器,请执行以下操作

    public class Main extends Application {
    
        public static void main(String[] args) {
            launch(args);
    
        }
    
        @Override
        public void start(Stage stage) throws Exception {
            stage.setTitle("Managment System");
            FXMLLoader loader = new FXMLLoader(getClass().getResource("/fxml/Main.fxml"));
    
            CarTableView model = new CarTableView();
            MainController mainController = new MainController(model);
    
            loader.setController(mainController);
    
            Scene scene = new Scene((Pane)loader.load(),1800,900);
            stage.setScene(scene);
            stage.show();
    
        }
    
    }
    

    并从 FXML 文件中删除 fx:controller 属性。

    然后,您可以在加载另一个 FXML 文件时使用相同的模型实例执行相同操作。


    一种相关的方法是使用控制器工厂:

    CarTableView model = new CarTableView() ;
    
    Callback<Class<?>, Object> controllerFactory = controllerType -> {
        if (controllerType == MainController.class) {
            return new MainController(model);
        } else {
            throw new IllegalStateException("Unexpected controller class: "+controllerType.getName());
        }
    };
    
    FXMLLoader loader = new FXMLLoader(getClass().getResource("/fxml/Main.fxml"));
    loader.setControllerFactory(controllerFactory);
    Scene scene = new Scene(loader.load(), 1800, 900);
    // ...
    

    在此版本中,您将 fx:controller 属性保留在 FXML 文件中。

    这里的基本思想是,控制器工厂是将控制器的类型映射到控制器实例的函数,因此您可以使用控制器工厂来配置控制器的创建方式。您可以使用反射来使其可重用(获取类的构造函数,检查它们中的任何一个是否采用类型为模型类型的单个参数,如果是则调用该构造函数,否则只调用默认构造函数)。

    您还可以使用这种技术来使用依赖注入框架(例如 Spring)来创建您的控制器:请参阅 Dependency Injection and JavaFX。当然,这意味着您可以使用 Spring 将模型注入到控制器中,这变得非常好。

    最后,请注意有一个 JavaFX 特定的依赖注入框架,afterburner.fx。这基本上在底层使用了这种技术,让您可以直接在控制器中简单地使用javax.inject 注释,因此您只需对模型进行注释以便自动注入它。如果您有一个需要大量注入的中大型应用程序,这是一个非常好的选择。

    【讨论】:

    • 好的,我理解这个想法,但我应该将此方法应用于每个单一个控制器。这是一种正确的做法还是只是在弄乱代码?
    • @Michael213 添加了更多信息。听起来您可能肯定要考虑集成 Spring 或使用 JavaFX。
    • 我尝试了您向我解释的解决方案(使用传递模型抛出构造函数),但编译器要求我在 fxml 文件中指定控制器:原因:javafx.fxml.LoadException:未指定控制器。跨度>
    • @Michael213 是的,抱歉:我跳过了一行。现已修复。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2020-08-02
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-04-07
    相关资源
    最近更新 更多