web-dev-qa-db-ja.com

同じシーンに新しいfxmlをロードする

2つのfxmlファイルがあります。

  • レイアウト(ヘッダー、メニューバー、コンテンツ)
  • アンカー(他のfxmlファイルのコンテンツ内に配置されることになっています)

「マスター」シーンからコンテンツスペース内に2番目のファイルをロードする方法を知りたいのですが。そして、それはjavaFXで作業するのが良いことですか、それとも新しいシーンをロードする方が良いでしょうか?

私はこのようなことをしようとしていますが、うまくいきません:

@FXML
private AnchorPane content;

@FXML
private void handleButtonAction(ActionEvent event) {        
    content = (AnchorPane) FXMLLoader.load("Vista2.fxml");
}

助けてくれてありがとう。

37
Andre

コードが機能しない理由

ローダーは新しいAnchorPaneを作成しますが、シーングラフの親に新しいペインを追加することはありません。

クイックフィックス

の代わりに:

content = (AnchorPane) FXMLLoader.load("Vista2.fxml");

書く:

content.getChildren().setAll(FXMLLoader.load("Vista2.fxml"));

コンテンツの子を新しいVistaに置き換えます。コンテンツ自体はシーングラフに残っているため、子を設定すると、同時にそれらもシーングラフにアタッチされます。

あなたが望む正確な動作を得るために、レイアウトをいじる必要があるかもしれません(例:AnchorPanesではなくStackPanesのようなレイアウトの自動サイズ変更で動作します)。

クイックフィックスを採用するだけでなく、以下にリンクする単純なフレームワークを確認することをお勧めします。これにより、目的の動作を取得するためのより汎用的なメカニズムが提供される可能性があります。

参照FXMLナビゲーションフレームワーク

メインシーンの一部でfxmlで制御されるコンテンツペインをスワップするための 小さなフレームワーク を作成しました。

フレームワークのメカニズムは、kithrilの回答で提案されているものと同じです。

  1. 外側のfxmlのメインペインは、子ペインのホルダーとして機能します。
  2. 外部fxmlのメインコントローラーは、子ペインの交換に使用できるパブリックメソッドを提供します。
  3. 便利なナビゲータクラスは、外部レイアウトのメインコントローラーで静的に初期化されます。
  4. ナビゲーターは、メインコンテナーに新しい子ペインをロードするためのパブリック静的メソッドを提供します(メインコントローラーでメソッドを呼び出すことにより)。
  5. 子ペインは、それぞれのfxmlローダーによってナビゲーターで生成されます。

フレームワークの理由

フレームワークはあなたの質問に答えるには行き過ぎのように思えますが、おそらくそうです。ただし、FXMLに関連する2つの最もよく尋ねられるトピックは次のとおりです。

  1. FXMLによって生成されたペイン間のナビゲーション(この質問)。
  2. FXMLコントローラー間でデータを渡す方法

ですから、このケースには小さなデモフレームワークが必要だと感じました。

フレームワーク出力のサンプル

最初の画面は、最初のVistaを表示するアプリケーションレイアウトを示しています。コンテンツは、メインアプリケーションレイアウトで定義されるヘッダーと、aliceblue色の交換可能な子コンテンツペインです。

Vista1

次の画面で、ユーザーは2番目のVistaに移動しました。これにより、メインレイアウトからの一定のヘッダーが保持され、元の子ペインが新しいサンゴ色の子コンテンツペインに置き換えられます。新しい子は、新しいfxmlファイルからロードされました。

Vista2

もっと重要なものをお探しですか?

この質問のサンプルフレームワークよりも広範囲で優れたサポートがある軽量フレームワークは、 afterburner.fx です。

もっと簡単なものをお探しですか?

シーンのルートを入れ替えるだけです: JavaFXのシーンの変更

その他のオプション?

アニメーション化されたトランジションなど: JavaFXのペイン間の切り替え

67
jewelsea

これがどれほど効果的かはわかりませんが、うまくいくようで、上記の方法よりもはるかに簡単です。

https://www.youtube.com/watch?v=LDVztNtJWOo

私がここで何が起こっているのかを理解している限り、これは(アプリケーションクラスのStart()メソッドで起こっていることと本当に似ています):

private void buttonGoToWindow3Action(ActionEvent event) throws IOException{
    Parent window3; //we need to load the layout that we want to swap
    window3 = (StackPane)FXMLLoader.load(getClass().getResource("/ScenePackage/FXMLWindow3"));

    Scene newScene; //then we create a new scene with our new layout
    newScene = new Scene(window3);

    Stage mainWindow; //Here is the magic. We get the reference to main Stage.
    mainWindow = (Stage)  ((Node)event.getSource()).getScene().getWindow();

    mainWindow.setScene(newScene); //here we simply set the new scene
}

ただし、Im Javaエキスパートではなく、プログラミングにはまったく新しいので、経験のある人が評価するのが良いでしょう。

編集:さらに簡単な方法を見つけました。

MainApplicationクラスに移動し、静的なステージparentWindowを作成します。

public static Stage parentWindow;
@Override
public void start(Stage stage) throws Exception {
    parentWindow = stage;

    Parent root = FXMLLoader.load(getClass().getResource("/ScenePackage/FXMLMainScene.fxml"));

    Scene scene = new Scene(root);

    stage.setScene(scene);
    stage.show();
}

これでメインステージにアクセスできるようになったので、プログラムのどこでもそのようなことをしてシーンを変更できます。

    Parent window1;
    window1 = FXMLLoader.load(getClass().getResource("/ScenePackage/FXMLWindow1.fxml"));

    //Scene newSceneWindow1 = new Scene(window1);

    Stage mainStage;
    //mainStage = (Stage)  ((Node)event.getSource()).getScene().getWindow();
    mainStage = MainApplication.parentWindow;
    mainStage.getScene().setRoot(newSceneWindow1); //we dont need to change whole sceene, only set new root.
6

マスク の私の例。

を使用して:

Main.getNavigation().load(View2.URL_FXML).Show();
Main.getNavigation().GoBack();
0
vas7n

ボタンが新しいfxmlファイルを呼び出すようにする方法を探しているなら、これは私のために働いた。

@FXML
private void mainBClicked(ActionEvent event) throws IOException {
    Stage stage;
    Parent root;
    stage=(Stage) ((Button)(event.getSource())).getScene().getWindow();
    root = FXMLLoader.load(getClass().getResource("MainMenu.fxml"));
    Scene scene = new Scene(root);
    stage.setScene(scene);
    stage.show();
}
0
Alekya

この場合、代わりに custom component を使用することをお勧めします。まず、コンテンツのカスタムコンポーネントを作成します。

_class Content2 extends AnchorPane {
    Content() {
        FXMLLoader loader = new FXMLLoader(getClass().getResource("Vista2.fxml");
        loader.setRoot(this);
        loader.setController(this);
        loader.load();
    }
}
_

_Vista2.fxml_ファイルのルートにあるAnchorPaneマークアップを_fx:root_に置き換えます。

_<fx:root type="javafx.scene.layout.AnchorPane" xmlns:fx="http://javafx.com/fxml">
    ...
</fx:root>
_

次に、カスタムイベントバインディングと矢印関数を使用して、これを簡単に行うことができます。イベントハンドラプロパティをContentクラスに追加します。

_private final ObjectProperty<EventHandler<ActionEvent>> propertyOnPreviousButtonClick = new SimpleObjectProperty<EventHandler<ActionEvent>>();

@FXML
private void onPreviousButtonClick(ActionEvent event) {
    propertyOnPreviousButtonClick.get().handle(event)
}

public void setOnPreviousButtonClick(EventHandler<ActionEvent> handler) {
    propertyOnPreviousButtonClick.set(handler);
}
_

最後に、カスタムイベントハンドラーをJavaコードまたはfxmlでバインドします。

_@FXML
onNextButtonClick() {
    Content2 content2 = new Content2();
    content2.setOnPreviousButtonClick((event) -> {
        Content1 content1 = new Content1();

        layout.getChildren().clear();
        layout.getChildren().add(content1);
    });

    layout.getChildren().clear();
    layout.getChildren().add(content2);    
}
_

コンテンツを動的に追加したくない場合は、setVisible()trueまたはfalseに追加するだけです

0
Clite Tailor

これにもこだわったほとんどの答えを試してみましたが、私が望んでいたものではなかったので、これを行うために与えられた理想を使用しました:

public class Main extends Application {
public static Stage homeStage;
@Override
public void start(Stage primaryStage) throws Exception{
    homeStage = primaryStage;
    Parent root = FXMLLoader.load(getClass().getResource("mainView.fxml"));
    root.getStylesheets().add(getClass().getResource("stylesheet/custom.css").toExternalForm());
    homeStage.setTitle("Classification of Living Organisms");
    homeStage.setScene(new Scene(root, 600, 500));
    homeStage.show();
}


public static void main(String[] args) {
    launch(args);
  }
}

これが私のメインクラスです。ランディングウィンドウ/ページmainView.fxmlを持つMain.Java。 mainController.Javaクラスでこれを行う前に、@ Tomaszのアイデアを少し使用しましたが、私は少し混乱していました。

public void gotoSubMenu(Event event) {
    Parent window1;
    try {
        window1 = FXMLLoader.load(getClass().getResource("src/displayView.fxml"));
        Stage window1Stage;
        Scene window1Scene = new Scene(window1, 600, 500);
        window1Stage = Main.homeStage;
        window1Stage.setScene(window1Scene);
    } catch (IOException e) {
        e.printStackTrace();
    }
}

srcディレクトリに「displayView.fxml」という2番目のfxmlファイルをロードする「window1」という新しい親ウィンドウを作成しました。メインビューステージのオブジェクトを作成し、シーンを、ルートがwindow1である新しく作成されたシーンに設定します。これが#JavaFXに登場する人たちの助けになることを願っています。

0
ConnelBLAZE

他の方がより良い解決策があるかもしれませんが、私の解決策は、外側のfxmlにVBoxのような単純なコンテナーを用意し、新しいコンテンツをロードして、コンテナーの子として追加することです。 1つまたは2つのフォームのみをロードする場合、これが先に進む方法かもしれません。ただし、より完全なフレームワークについては、このブログ投稿が役立つことがわかりました: https://blogs.Oracle.com/acaicedo/entry/managing_multiple_screens_in_javafx1 ファンシーな移行を含む彼女のフレームワークのソースコード。トップレベルのシーンを管理するためのものですが、内部コンテンツ領域の管理にも簡単に適応できることがわかりました。

0
kithril