Javax:ListView:通过在ListView中选择项来加载控制器

Javax:ListView:通过在ListView中选择项来加载控制器,java,listview,javafx,javafx-8,Java,Listview,Javafx,Javafx 8,我有一个视图,有一个列表视图和一个窗格。我想将控制器添加为列表视图的项目,当我单击其中一个列表视图元素时,将窗格的内容设置为其控制器内容 例如,我为每个控制器设置了水果控制器和蔬菜控制器,当然还有相应的.fxml,当我单击第一个元素时,将窗格s元素设置为水果的tableView,否则设置为蔬菜的tableView。我尝试使用等等,但我不知道如何切换内容,以及如何在ListView中将自定义名称显示为元素名称。你知道吗 编辑: 我在这里和这里找到了部分解决方案 但问题仍然存在,我不知道如何以及在何

我有一个视图,有一个
列表视图
和一个
窗格
。我想将控制器添加为
列表视图
的项目,当我单击其中一个列表视图元素时,将
窗格
的内容设置为其控制器内容

例如,我为每个控制器设置了
水果控制器
蔬菜控制器
,当然还有相应的
.fxml
,当我单击第一个元素时,将
窗格
s元素设置为水果的tableView,否则设置为蔬菜的tableView。我尝试使用
等等,但我不知道如何切换内容,以及如何在ListView中将自定义名称显示为元素名称。你知道吗

编辑:

我在这里和这里找到了部分解决方案
但问题仍然存在,我不知道如何以及在何处放置
标记,以便在单击某个项目时加载它。

您可以使用列表视图的选择模型注册一个侦听器,并在选择更改时加载相应的视图

例如,假设你有

public class View {

    private final String name ;
    private final Class<?> controllerType ;

    // You could assume that the resource is name+".fxml" if you want to rely on conventions like that
    // That would eliminate the need for another field here, but would prevent
    // e.g. names with whitespace etc.
    private final String resource ;

    public View(String name, Class<?> controllerType, String resource) {
        this.name = name ;
        this.controllerType = controllerType ;
        this.resource = resource ;
    }

    public String getName() {
        return name ;
    }

    public Class<?> getControllerType() {
        return controllerType ;
    }

    public String getResource() {
        return resource ;
    }

    @Override
    public String toString() {
        return name ;
    }
}
公共类视图{
私有最终字符串名;
私有最终类控制器类型;
//如果希望依赖这样的约定,可以假定资源为name+“.fxml”
//这将消除对另一个领域的需求,但会阻止
//例如,带有空格的名称等。
私有最终字符串资源;
公共视图(字符串名称、类控制器类型、字符串资源){
this.name=名称;
this.controllerType=controllerType;
这个资源=资源;
}
公共字符串getName(){
返回名称;
}
公共类getControllerType(){
返回控制器类型;
}
公共字符串getResource(){
返回资源;
}
@凌驾
公共字符串toString(){
返回名称;
}
}
然后在FXML中:


在控制器中:

package app ;

public class MainController {

    @FXML
    private BorderPane root ;

    @FXML
    private ListView<View> selector ;

    public void initialize() {
        selector.getSelectionModel().selectedItemProperty().addListener((obs, oldView, newView) -> {
            if (newView == null) {
                root.setCenter(null);
            } else {
                // assumes each FXML is in the same package as its controller
                // (which I think is a nice way to organize things)
                FXMLLoader loader = new FXMLLoader(newView.getControllerType().getResource(newView.getResource()));
                try {
                    root.setCenter(loader.load());
                } catch (IOException exc) {
                    // unrecoverable...
                    throw new UncheckedIOException(exc);
                }
            }
        });

        selector.getItems().addAll(
            new View("Fruits", FruitsController.class, "Fruits.fxml"),
            new View("Vegetables", VegetablesController.class, "Vegetables.fxml")
        );
    }
}
package应用程序;
公共类主控制器{
@FXML
私有边界根;
@FXML
私有列表视图选择器;
公共无效初始化(){
selector.getSelectionModel().SelectEditeProperty().addListener((obs、oldView、newView)->{
if(newView==null){
root.setCenter(null);
}否则{
//假设每个FXML与其控制器位于同一个包中
//(我认为这是一种很好的组织方式)
FXMLLoader=newFXMLLoader(newView.getControllerType().getResource(newView.getResource());
试一试{
root.setCenter(loader.load());
}捕获(IOException){
//无法恢复。。。
抛出新的未选中异常(exc);
}
}
});
selector.getItems().addAll(
新视图(“Fruits”,FruitsController.class,“Fruits.fxml”),
新视图(“蔬菜”,vegetablescoontroller.class,“vegests.fxml”)
);
}
}

如果所有控制器都具有公共功能,则可以使它们实现公共接口(例如,
ProductsController
),并使用
ProductsController currentController=loader.getController()从加载程序检索当前控制器加载新FXML后。(您也可以将
视图中的
控制器类型
更改为
Classic。最好不要使用
来执行此操作。只需使用列表视图的选择模型注册一个侦听器,并在选择更改时在控制器中加载新的FXML。是的,这是我的解决方案,但我有9-10项,而且列表随着时间的推移而不断增长,所以我认为有一种更简单的方法,在我向列表中添加新项目时,不必每次都编写加载程序。你为什么说“最好不要这样做”?这是一种不好的方式,或者根本不可能?我不确定我是否理解。您只需要选择一个侦听器,然后根据选择的内容选择FXML文件。然后为该FXML文件创建一个加载程序并加载它。(我想我不明白“写入”加载程序是什么意思。)如果你使用
,你基本上必须加载所有可能的FXML文件,并以某种方式隐藏那些你不想显示的文件,这将更加复杂,并将所有这些UI始终保留在内存中。也许如果你不能轻松地使用侦听器,请发布一些代码,说明你是如何尝试这样做的。嗯……你是对的,将所有UI保留在内存中是个坏主意。将侦听器添加到我的listview中不是问题。问题是我必须将所有
.fxml
路径保留在此控制器中,然后询问lisview的选定项:你是xController吗?…你是yController吗?如果其中一个匹配,则加载它。但如果不太清楚,我会发布一个cod几分钟后。只需为您的列表视图定义一个处理该问题的自定义类型。是的,正如您所写,我有一个由所有控制器实现的接口,因此我认为这是我将使用的解决方案,它比我所使用的要简单得多,也更容易理解。@Sunflame如果您愿意,您可以创建
视图
枚举,并且仍然可以完全按照当然,我会更好地使用这个类,但我认为我必须使用这个资源,因为我的名字被翻译成几种语言,而且单词之间也有空格,所以如果我理解正确,我就不能用你在资源上面的注释中写的那种方式,`root.setCenter(loader.load())?