7

JavaFX と FXML を使用して作成した GUI があります。

この GUI には多くのコンポーネントがあり、それらすべてが一度に必要になるわけではありません。

たとえば、サーバー パーツから都市のリストを受け取る GUI を想像してみてください。各都市は独自のタブで説明されています (そして多くのノードで説明されています)。都市のセットには 30 の要素が含まれています。

GUI が起動されると、サーバーに都市のリストを要求します。サーバーは都市のランダムな「サブセット」を返します (つまり、モスクワ + リガ + ニューヨーク、サンクトペテルブルク + 東京、アムステルダムのみ、または 30 都市すべてを 1 つのセットにすることができます)。

そう。ノード ツリーに 30 個のタブすべてを含める必要はありません (メモリを「食べる」だけで、それ以上のものは何もないと思います)。

GUI の各時点でのタブの数を管理したいと考えています。

私が持っている最初の簡単な解決策は次のとおりです。

  1. すべての都市のコンポーネントを含む FXML ファイルを作成します
  2. コントローラー クラスでの初期化中に、不要なタブを削除します。

このソリューションには問題があります。tabPane.getTabs().remove(index)まず、タブとそのすべてのコンテンツをノード ツリーから本当に削除するかどうかはわかりません。第 2 に、不要なタブはすべて削除される前に初期化されるため、とにかくメモリとリソースを使用し、GUI が必要以上に遅くなる可能性があります。

私が持っている2番目の解決策は次のとおりです。

  1. 多くの FXML を作成します。すべての都市に 1 つ、都市ごとに 1 つ、都市の組み合わせごとに 1 つ。

しかし、多くの FXML への道があるため、このソリューションも役に立ちません。

私が夢見る解決策:

  1. 都市ごとに 1 つの FXML ファイルを作成し、タブ付きのメイン アプリ用に 1 つの FXML ファイルを作成します。
  2. 必要に応じて、FXML シティ ファイルのコンテンツを動的にタブに読み込みます。

したがって、誰かがこのタスクに関するアイデアを持っているか、解決策を知っている場合は、それを手伝ってください...

4

1 に答える 1

11

わかりました、私があなたを正しく理解していれば、これがビクトリアの提案です。
メインアプリの 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 ごとにコントローラーを定義するか、すべてのコントローラー クラスを 1 つだけ定義して、fXMLLoader.setController(new CommonCityController());都市の fxml ファイルをロードする前に同様に設定します。

HTH。

于 2012-08-28T15:59:52.927 に答える