7

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

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

例如,假设一个 GUI 从其服务器部分接收城市列表。每个城市都在其自己的选项卡上进行了描述(并用许多节点进行了描述)。城市集包含 30 个元素。

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

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

我想管理我在 GUI 上每个时刻拥有的选项卡数量。

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

  1. 创建一个 FXML 文件,其中包含所有城市的组件
  2. 在控制器类的初始化过程中,删除不需要的选项卡。

我有这个解决方案的问题。首先,我不知道是否tabPane.getTabs().remove(index)真的从节点树中删除了选项卡及其所有内容。其次,所有不需要的选项卡将在它们被删除之前被初始化,因此它们无论如何都会使用内存和资源,而且我的 GUI 可能比它必须的要慢。

我的第二个解决方案是:

  1. 制作很多 FXML。一个用于所有城市,一个用于每个城市,一个用于每个城市组合。

但是会有很多 FXML 的方法,所以这个解决方案也没有用。

我梦寐以求的解决方案:

  1. 为每个城市创建一个 FXML 文件,并为带有选项卡的主应用程序创建一个文件。
  2. 需要时将 FXML 城市文件内容动态加载到选项卡中。

所以,如果有人对此任务有任何想法,或者知道解决方案,请帮助我......

4

1 回答 1

11

好的,如果我理解正确,这是我的建议 Victoria;
假设主应用程序 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 定义一个控制器,或者为所有它们定义一个控制器类,并fXMLLoader.setController(new CommonCityController());在加载城市 fxml 文件之前设置它。

HTH。

于 2012-08-28T15:59:52.927 回答