JavaFX控制器到控制器 - 访问UI控件 [英] JavaFX controller to controller - access to UI Controls

查看:201
本文介绍了JavaFX控制器到控制器 - 访问UI控件的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

在研究我的MVC javaFX之后 - 问题没有任何解决方案超过2天,我现在决定发布它:

After research on my MVC javaFX - Problem without any solution for more than 2 days, I decided now to post it:

我有一个应用程序窗口除以不同的SplitPanes和每个Panes都有自己的.fxml表单,由自己的控制器控制。

I've one application Window divided by different SplitPanes and each of this Panes has its own .fxml-form controlled by its own controller.

我的问题是:如何才能访问外部UI- Controlls?
例如:单击TableView行会影响填写其他表单中的Textfields。

My Question is: How is it possible to get access to external UI-Controlls? For Example: Clicking on a TableView-row should effect to fill Textfields in an other Form.

我当前(不工作)解决方案如下:

My current (not working) Solution is as follows:

第一个控制器:提供实例

public static SpielerController instance;
    public SpielerController() {};
    public static SpielerController getInstance()
    {   
        if(SpielerController.instance==null)
        {
            synchronized (SpielerController.class)
            {
                if(SpielerController.instance == null)
                {
                    SpielerController.instance = new SpielerController();
                }
            }
        }

        return SpielerController.instance;

    }

第二控制器:获取实例并调用方法

SpielerController.getInstance().setPID(Integer.toString(pid));

结果是:


  • 可以将值pid传递给调用的方法并将其打印出来( System.out.println(pid);

无法设置值,例如 TextField1.setText(pid);

是否有可能以这种方式设置值,当是 - 如何?

Is it possible to set values in this way and when yes - how?

是否有其他(更好)的方式来满足这种需求?

Is there maybe an other (better) way to meet this demand?

推荐答案

不要公开UI控件或维护对其他控制器的引用。相反,在控制器中公开一些可观察的数据,并使用绑定将所有内容绑定在一起。

Don't expose the UI controls or maintain references to other controllers. Instead, expose some observable data in the controllers, and use bindings to bind everything together.

例如,假设您有一个显示<$ c的Table.fxml文件$ c> TableView< Person> ( Person 只是示例数据类)并且具有相应的控制器:

For example, suppose you have a Table.fxml file which displays a TableView<Person> (Person is just the example data class) and has a corresponding controller:

public class TableController {

    @FXML
    private TableView<Person> table ;

    private final ReadOnlyObjectWrapper<Person> selectedPerson = new ReadOnlyObjectWrapper<>();
    public ReadOnlyObjectProperty<Person> selectedPersonProperty() {
        return selectedPerson.getReadOnlyProperty() ;
    }
    public final Person getSelectedPerson() {
        return selectedPersonProperty().get();
    }

    public void initialize() {
        selectedPerson.bind(table.getSelectionModel().selectedItemProperty());
    }
}

第二个FXML(可能包含用于编辑的文本字段)与表中所选项目相关联的数据)Editor.fxml与相应的 EditorController 类:

And a second FXML (perhaps containing text fields for editing the data associated with the selected item in the table) Editor.fxml with a corresponding EditorController class:

public class EditorController {

    @FXML
    private TextField nameTextField ;

    private ObjectProperty<Person> person = new SimpleObjectProperty<>();
    public ObjectProperty<Person> personProperty() {
        return person ;
    }
    public final Person getPerson() {
        return personProperty().get();
    }
    public final void setPerson(Person person) {
        personProperty().set(person);
    }

    public void initialize() {

        // update text field bindings when person changes:
        personProperty().addListener((obs, oldPerson, newPerson) -> {
            if (oldPerson != null) {
                oldPerson.nameProperty().unbindBidirectional(nameTextField.textProperty());
            }
            if (newPerson != null) {
                newPerson.nameProperty().bindBidirectional(nameTextField.textProperty());
            }
        }
    }
}

现在当您加载FXML文件时,您只需要绑定两个公开的属性:

Now when you load the FXML files you just need to bind the two exposed properties:

FXMLLoader tableViewLoader = new FXMLLoader(getClass().getResource("Table.fxml"));
Parent tableView = tableViewLoader.load();
TableController tableController = tableViewLoader.getController();

FXMLLoader editorLoader = new FXMLLoader(getClass().getResource("Editor.fxml"));
Parent editorView = editorLoader.load();
EditorController editorController = editorLoader.getController();

// assemble views...

// bind properties from controllers:
editorController.personProperty().bind(tableController.selectedPersonProperty());

此处有多种方法可以管理详情,例如:您可以使用侦听器而不是绑定来获得更多值的更新控制等等。但基本思路是从控制器中公开必要的数据并观察它,而不是将不同的控制器紧密耦合在一起。

There are various ways to manage the details here, e.g. you can use listeners instead of bindings to gain more control as to when values are updated, etc. But the basic idea is to expose the data necessary from the controllers and observe it, instead of tightly coupling the different controllers together.

如果有足够的数据需要在两个控制器之间共享,这会变得难以处理,那么您可以将这些数据捆绑到模型 class并使用完全相同的技术在控制器之间共享模型。如果您愿意放弃使用 fx:controller 属性在FXML中设置控制器,则可以让控制器接受模型在其构造函数中引用;例如

If there is sufficient data that needs to be shared between two controllers that this gets unwieldy, then you can bundle those data into a Model class and use exactly the same technique to share the model between the controllers. If you are willing to forego setting the controller in the FXML with a fx:controller attribute, you can have the controller accept a Model reference in its constructor; for example

public class TableController {
    @FXML
    private TableView<Person> table ;
    private Model model ;
    public TableController(Model model) {
        this.model = model ;
    }

    public void initialize() {
        table.getSelectionModel().selectedItemProperty().addListener((obs, oldPerson, newPerson) 
            -> model.setSelectedPerson(newPerson));
    }
}

并且编辑器只观察模型中的属性:

and the editor just observes the property in the model:

public class EditorController {
    private Model model ;
    @FXML
    private TextField nameTextField ;

    public EditorController(Model model) {
        this.model = model ;
    }

    public void initialize() {
        model.selectedPersonProperty().addListener((obs, oldPerson, newPerson) 
            -> nameTextField.setText(newPerson.getName()));
    }
}

然后汇编代码看起来像

Model model = new Model();
TableController tableController = new TableController(model);
FXMLLoader tableLoader = new FXMLLoader(getClass().getResource("Table.fxml"));
tableLoader.setController(tableController);
Parent tableView = tableLoader.load();

EditorController editorController = new EditorController(model);
FXMLLoader editorLoader = new FXMLLoader(getClass().getResource("Editor.fxml"));
editorLoader.setController(editorController);
Parent editorView = editorLoader.load();

// assemble views...

在此版本中,FXML文件不能有 fx:controller 属性。

In this version, the FXML files cannot have fx:controller attributes.

另一种变体可以在 FXMLLoader 上设置控制器工厂,以便它加载由<$ c定义的类$ c> fx:controller 属性,但是您可以控制它如何加载它们(即它可以将模型传递给构造函数)。

Another variant can set the controller factory on the FXMLLoader, so that it loads classes defined by the fx:controller attribute, but you control how it loads them (i.e. it can pass a model to the constructor).

最后,您可以考虑使用专用依赖注入框架将模型注入控制器。 afterburner.fx 非常适合。

Finally, you might consider a dedicated dependency injection framework for injecting a model into the controllers. afterburner.fx is excellent for this.

这篇关于JavaFX控制器到控制器 - 访问UI控件的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆