我对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
所以我的问题是:
提前谢谢你, solarisx
答案 0 :(得分:6)
您似乎将不同的概念混合在一起,这些概念是截然不同的。首先,舞台可以理解为屏幕上的一个窗口。它有一个Scene对象,它保存实际的SceneGraph。在您的示例中,您正在创建一个新的Stage和一个新的Scene,它将填充第二个fxml文件的内容。这意味着,如果正常工作,会弹出第二个窗口,其中包含您的内容。我认为这不是你想要达到的目标。
此外,当FXMLLoader读取文件时,它会查找指定为其控制器的类,并通过反射构造它的实例。这意味着当您在fxml文件的控制器的构造函数中调用load方法时,您正在加载它,导致无限循环。
最后要理解的是load()
返回的对象是一个任意节点,可以像任何其他节点一样放入应用程序的SceneGraph中。
因此,为了使您的概念有效,您应该做到以下几点:
load()
方法。调用load()
后,您可以通过getController()
和getRoot()
检索fxml文件的控制器和根对象。然后,您可以像使用逻辑中的任意对象一样使用它们。