2017-07-19 54 views
0

我有看法,并有ListViewPane。我想补充控制器为ListView的项目,当我点击ListView的元素之一,集Pane的内容,它的控制器内容,Javax:ListView:通过选择ListView中的项目加载控制器

比如我有FruitsControllerVegetablesController,当然还有相应的.fxml为每个控制器,当我点击第一个元素设置Pane的元素tableView的水果,否则与蔬菜tableview。我尝试了whith <fx:include source=Fruits.fxml>等,但我不知道如何切换内容,以及如何在ListView中将自定义名称显示为元素名称。那么你有什么想法吗?

编辑:

,我发现这里的部分和How can I Populate a ListView in JavaFX using Custom Objects?这里JavaFX - ListView Item with an Image Button 解决方案,但问题仍然存在,我不知道如何以及在何处把<fx:include>标签,加载它,当我点击一个项目。

+0

这可能最好不要用''来完成。只需向列表视图的选择模型注册监听器,并在控制器中选择更改时加载新的FXML。 –

+0

是的,这是我的解决方案,但我有9-10项,并且列表随着时间增长,所以我认为有一种更简单的方法,在每次添加新的时候都不写入加载程序项目列表。你为什么说“最好不要这样做”?这是一种糟糕的方式,或者仅仅是不可能的? – Sunflame

+0

不知道我明白。您只需要一个监听器来选择,然后根据所选内容选择FXML文件。然后*为该FXML文件创建一个加载器并加载它。 (我想我不明白“写入”加载程序的含义。)如果使用'',您基本上必须加载所有可能的FXML文件,并以某种方式隐藏不想显示的文件,这会更加复杂,并且会一直将所有这些UI保存在内存中。也许如果你不能以简单的方式使用监听器发布一些代码来展示你如何去做。 –

回答

1

您只需向列表视图的选择模型注册侦听器,并在选择更改时加载相应的视图。

例如,假设你在FXML有

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 ; 
    } 
} 

然后:

<!-- imports, namespaces omitted --> 

<BorderPane fx:id="root" fx:controller="app.MainController" ... > 
    <left> 
     <ListView fx:id="selector"/> 
    </left> 
</BorderPane> 

,并在控制器:

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") 
     ); 
    } 
} 

如果所有的控制器都具有共同的功能,可以使它们实现一个通用接口(例如ProductsController),并检索当前控制器f加载新的FXML后,从ProductsController currentController = loader.getController();开始从加载程序。 (在这种情况下,您也可以将View中的controllerType更改为Class<? extends ProductsController>)。

+0

是的,就像你写的一样,我有一个由所有控制器实现的接口,所以我认为这是我将使用的解决方案,它使用起来更加简单和易于理解。 – Sunflame

+0

@Sunflame你可以让'View'成为一个枚举,如果你愿意并且仍然做同样的事情,当然。 –

+0

我会更好地使用这个类,但是我认为我必须使用这个资源,因为我的_names_被翻译成多种语言,并且在单词之间也有空格,所以如果我理解正确,我不能用你在上面的注释中写的方式_resource_, – Sunflame