如何动态地将内容加载到JavaFX选项卡?

时间:2012-08-27 17:09:45

标签: javafx-2 fxml

我有一个使用JavaFX和FXML制作的GUI。

这个GUI有很多组件,并不是所有组件都需要在一个时刻。

例如,想象一下从服务器部分接收城市列表的GUI。 每个城市都在其自己的选项卡上进行描述(并使用大量节点进行描述)。这组城市包含30个元素。

启动GUI时,它会向服务器请求城市列表。 服务器返回一个随机的“子集”城市(因此,它可以是莫斯科+里加+纽约或圣彼得堡+东京,或只有阿姆斯特丹,或一组中的所有30个城市)。

因此。我没有必要在我的节点树中拥有所有30个选项卡(我想它们只会“吃掉”内存而已。)

我想管理GUI上每时每刻的标签数量。

我的第一个简单解决方案如下:

  1. 创建一个包含所有城市组件的FXML文件
  2. 在控制器类初始化期间,删除不需要的选项卡。
  3. 我对此解决方案存在问题。首先,我不知道tabPane.getTabs().remove(index)是否真的从节点树中删除了选项卡及其所有内容。其次,所有不需要的选项卡将在删除之前初始化,因此无论如何它们都将使用内存和资源,而且我的GUI可能比它更慢。

    我的第二个解决方案是:

    1. 制作大量的FXML。一个适用于所有城市,每个城市一个,每个城市组合一个。
    2. 但是会有很多FXML,所以这个解决方案也没用。

      我梦寐以求的解决方案:

      1. 为每个城市创建一个FXML文件,为主应用创建一个带标签的文件。
      2. 在需要时动态地将FXML城市文件内容加载到选项卡中。
      3. 所以,如果有人对此任务有任何想法,或者知道解决方案,请帮助我...

1 个答案:

答案 0 :(得分:10)

好的,如果我理解正确的话,这是我的建议维多利亚;
假设主应用程序FXML中包含TabPane

// other controls
<TabPane fx:id="tabPane" id="tabPane">
   <tabs>
   </tabs>
</TabPane>
// other controls

在主控制器中:

// TabPane in fxml
@FXML
private TabPane tabPane;

// The FXMLLoader
private FXMLLoader fXMLLoader = new FXMLLoader();

// City list fetched from server
private String[] cityList = {"Moscow", "Stambul", "New York", "Bishkek"};

// OPTIONAL : Map for "city name - city fxml controller" pairs
private Map<String, Object> cityControllerMap = new HashMap<String, Object>();

// Belows are in init method

// Add only tabs dynamically but not their content
for (String city : cityList) {
    tabPane.getTabs().add(new Tab(city));
}

// It is important to call it before adding ChangeListener to the tabPane to avoid NPE and
// to be able fire the manual selection event below. Otherwise the 1st tab will be selected
// with empty content.
tabPane.getSelectionModel().clearSelection();

// Add Tab ChangeListener
tabPane.getSelectionModel().selectedItemProperty().addListener(new ChangeListener<Tab>() {
    @Override
    public void changed(ObservableValue<? extends Tab> observable, Tab oldValue, Tab newValue) {
        System.out.println("Tab selected: " + newValue.getText());
        if (newValue.getContent() == null) {
            try {
                // Loading content on demand
                Parent root = (Parent) fXMLLoader.load(this.getClass().getResource(newValue.getText() + ".fxml").openStream());
                newValue.setContent(root);

                // OPTIONAL : Store the controller if needed
                cityControllerMap.put(newValue.getText(), fXMLLoader.getController());

            } catch (IOException ex) {
                ex.printStackTrace();
            }
        } else {
            // Content is already loaded. Update it if necessary.
            Parent root = (Parent) newValue.getContent();
            // Optionally get the controller from Map and manipulate the content
            // via its controller.
        }
    }
});
// By default, select 1st tab and load its content.
tabPane.getSelectionModel().selectFirst();

如果您决定存储控制器,您可以为每个城市fxml定义一个控制器,或者为所有城市定义一个控制器类,并在加载city fxml文件之前将其设置为fXMLLoader.setController(new CommonCityController());

HTH。