6

私はjavaとjavafxにまったく慣れておらず、解決できない問題があります。新しいカスタムコントロールをjavafxシーンに動的に追加する必要があります。さらに、メインコントロールと追加されたコントロールの間の相互作用が必要です。私はすでにウェブでいくつかの有用な情報を見つけましたが、それをまとめることができませんでした。

だから私は説明のために小さな例を作ります:

メインクラス:

public class Test_TwoController extends Application {

    @Override
    public void start(Stage stage) throws Exception {
        Parent root = FXMLLoader.load(getClass().getResource("Fxml1.fxml"));
        Scene scene = new Scene(root);                  
        stage.setScene(scene);
        stage.show();
    }    
    public static void main(String[] args) {
        launch(args);
    }
}

メインのfxml:

<AnchorPane id="fxml1_anchorpane_id" fx:id="fxml1_anchorpane" prefHeight="206.0" prefWidth="406.0" xmlns:fx="http://javafx.com/fxml" fx:controller="test_twocontroller.Fxml1Controller">
  <children>
    <HBox id="fxml1_hbox_id" fx:id="fxml1_hbox" prefHeight="200.0" prefWidth="400.0">
      <children>
        <Button id="fxml1_button_id" fx:id="fxml1_button" mnemonicParsing="false" onAction="#button_action" prefHeight="200.0" prefWidth="200.0" text="Button" />
      </children>
    </HBox>
  </children>
</AnchorPane>

およびそのコントローラー:

public class Fxml1Controller implements Initializable {

    @FXML HBox hbox;
    @FXML Button button;

    @Override
    public void initialize(URL url, ResourceBundle rb) { }

    public void button_action(ActionEvent event) throws IOException {
        // 1. add an instance of Fxml2 to hbox
        // 2. change to tab2 in new Fxml2
        // or
        // notify Fxml2Controller to change to tab2 in Fxml2
    }
}

そして今、動的に追加するコントロール:

そのfxml:

<AnchorPane id="fxml2_anchorpane_id" fx:id="fxml2_anchorpane" maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" prefHeight="200.0" prefWidth="200.0" xmlns:fx="http://javafx.com/fxml" fx:controller="test_twocontroller.Fxml2Controller">
  <children>
    <TabPane id="fxml2_tabpane_id" fx:id="fxml2_tabpane" prefHeight="200.0" prefWidth="200.0" tabClosingPolicy="UNAVAILABLE">
      <tabs>
        <Tab id="fxml2_tab1_id" fx:id="fxml2_tab1" text="tab1">
          <content>
            <AnchorPane id="Content" minHeight="0.0" minWidth="0.0" prefHeight="180.0" prefWidth="200.0" />
          </content>
        </Tab>
        <Tab id="fxml2_tab2_id" fx:id="fxml2_tab2" onSelectionChanged="#onSelectionChanged" text="tab2">
          <content>
            <AnchorPane id="Content" minHeight="0.0" minWidth="0.0" prefHeight="180.0" prefWidth="200.0" />
          </content>
        </Tab>
      </tabs>
    </TabPane>
  </children>
</AnchorPane>

とコントローラー:

public class Fxml2Controller {

    @FXML TabPane tabpane;
    @FXML Tab tab1;
    @FXML Tab tab2;

    public Fxml2Controller() throws IOException {
        Parent root = FXMLLoader.load(getClass().getResource("Fxml2.fxml"));
        Scene scene = new Scene(root);        
        Stage stage = new Stage();
        stage.setScene(scene);        
    }    

    public void onSelectionChanged(Event e) throws IOException {

        FXMLLoader loader = new FXMLLoader();
        // how can i get the current Fxml1 anchorpane instance?
        AnchorPane root = (AnchorPane) loader.load(getClass().getResource("Fxml1.fxml").openStream());

        Button b = (Button)root.lookup("#fxml1_button_id");        
        b.setText("New Button Text"); // dont change the buttons text!!!               
}
}

使用法は次のとおりです。fxml2をfxml1のhboxに追加する必要があります。次に、fxml1でボタンをクリックした後、fxml2のタブが変更されます。あなたはその画像を見るかもしれませんhttp://s13.postimage.org/uyrmgylo7/two_controlls.png

だから私の質問は:

  • 1つ以上のfxml2コントローラーをfxml1のhboxに追加するにはどうすればよいですか?
  • あるコントロールに別のコントロールからアクセスしたり、コントロール間で通信したりするにはどうすればよいですか?詳細については、Fxml2ControllerのonSelectionChanged()メソッドを参照してください。

よろしくお願いします、solarisx

4

1 に答える 1

6

あなたは、明確なかなりの数の概念を混ぜ合わせたようです。まず第一に、ステージは画面上のウィンドウとして理解することができます。実際のSceneGraphを保持するSceneオブジェクトがあります。この例では、2番目のfxmlファイルのコンテンツで埋められる新しいステージと新しいシーンを作成しています。これは、動作している場合、あなたのものを含む2番目のウィンドウがポップアップすることを意味します。これはあなたが達成したいことではないと思います。

さらに、FXMLLoaderはファイルを読み取るときに、コントローラーとして指定されているクラスを探し、リフレクションを介してそのインスタンスを構築します。これは、ロードしているfxmlファイルのコントローラーのコンストラクターでloadメソッドを呼び出すと、無限ループが発生することを意味します。

最後に理解しておくべきことは、load()返されるオブジェクトは、他のノードと同じようにアプリケーションのSceneGraphに配置できる任意のノードであるということです。

したがって、コンセプトを機能させるには、次のようにする必要があります。

  1. 現在2番目のコントローラーのコンストラクターにあるloading-codeを、最初のコントローラーのbutton_Actionメソッドに移動します。
  2. button_actionのnew-stage-new-sceneコードを破棄し、FXMLLoaderによって返されたノードを取得して、HBoxの子に追加します。
  3. 2番目の質問では、静的メソッドを呼び出す代わりにFXMLLoaderのインスタンスを実際に作成し、その中でメソッドを使用すると、コントローラーインスタンスを取得できますload()。呼び出した後、とを介してload()fxmlファイルのコントローラーとルートオブジェクトを取得できます。その後、ロジック内の任意のオブジェクトと同じように使用できます。getController()getRoot()
于 2012-11-20T09:24:30.667 に答える