JavaFX-在fxml和更新列表视图之间传递值

时间:2017-11-08 06:02:48

标签: listview javafx

我有一个包含 hbox(root)和2个vbox 的场景,每个vbox包含单独的fxml文件和控制器。第一个vbox包含一个按钮和textfield,第二个包含一个listview,所以我需要的是当我单击textfield上的按钮值时应该传递给listview并更新而不加载一个全新的阶段。
注意:我使用

找到了一个有效的解决方案

fx:include id="v1"作为vbox儿童

在fxml中并初始化主控制器中的控制器,但遗憾的是,如果我想要替换vbox子进程 新的fxml意味着,我该怎么办?那么任何简单的工作解决方案呢?

这是我的maincontroller.java

public class MainController implements Initializable{
    @FXML
    private VBox v1;

    @FXML
    private VBox v2;

    @Override
    public void initialize(URL url, ResourceBundle rb) {
        try {
            v1.getChildren().add(FXMLLoader.load(getClass().getResource("voneFX.fxml")));
            v2.getChildren().add(FXMLLoader.load(getClass().getResource("vtwoFX.fxml")));
          } catch (IOException ex) {
              Logger.getLogger(FXMLDocumentController.class.getName()).log(Level.SEVERE, null, ex);
          }
     }
}   

voneController.java

public class voneController  {

    @FXML private TextField txt1;
    @FXML private Button btn1Send;

    @FXML private void btn1SendClicked(ActionEvent event){
        //Here i would like to call updateListView method
    }
}

votwoController.java

public class vtwoController{

     @FXML
    private ListView<ListModel> sampleListview;
    ObservableList<ListModel> items = FXCollections.observableArrayList ();

    public void updateListView() {
      //This is the method which is called when user hit the button.
    }
}

1 个答案:

答案 0 :(得分:0)

要制作您想要的东西,您需要访问控制器(控制器本身必须能够相互通信)。 FXMLLoader提供了几种访问控制器的选项。第一个选项是自动将f include中包含的fxml组件注入fxml文件中。

<fx:include fx:id="childView" source="child.fxml"/>

为了注入控制器,必须使用后缀Controller在child.fxml中指定的名称声明fx:id中指定的控制器类型的字段。当然,使用@FXML进行注释。

public class MainController {
    @FXML
    private ChildController childViewController;

    ...
}

如果您要使用动态变化的上下文,您可以手动创建控制器并将其传递给FXMLLoader,这将通过注入相应的字段或只是选择初始化的实例来初始化它。

此处,首先致电FXMLLoader#load(),然后FXMLLoader#getController(),这一点非常重要。

FXMLLoader loader = new FXMLLoader(getClass().getResource("/resource/layout/child.fxml"));
Parent parent = loader.load();

ChildController controller = loader.getController();

手动创建控制器时,您必须先调用FXMLLoader#setController()然后再调用FXMLLoader#load()

ChildController controller = new ChildController();

FXMLLoader loader = new FXMLLoader(getClass().getResource("/resource/layout/child.fxml"));
loader.setController(controller);
Parent parent = loader.load();

因此,控制器之间的通信是微不足道的,我认为没有必要解释。

<强>更新

如何在对象之间进行通信的示例。 这些是使用该应用程序的两个视图:

child.fxml

<?xml version="1.0" encoding="UTF-8"?>

<?import javafx.scene.control.Button?>
<?import javafx.scene.control.Label?>
<?import javafx.scene.control.TextField?>
<?import javafx.scene.layout.HBox?>

<HBox alignment="CENTER_LEFT" spacing="5.0" xmlns="http://javafx.com/javafx/8.0.141" xmlns:fx="http://javafx.com/fxml/1" fx:controller="sample.ChildController">
   <children>
      <Label text="Child View" />
      <TextField fx:id="textField" HBox.hgrow="ALWAYS" />
      <Button mnemonicParsing="false" text="Send to parent" onAction="#handleSendButton"/>
   </children>
</HBox>

sample.fxml

<?xml version="1.0" encoding="UTF-8"?>

<?import javafx.scene.control.Button?>
<?import javafx.scene.control.TextField?>
<?import javafx.scene.layout.HBox?>
<?import javafx.scene.layout.VBox?>

<VBox maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" prefHeight="400.0" prefWidth="600.0" spacing="5.0" xmlns="http://javafx.com/javafx/8.0.141" xmlns:fx="http://javafx.com/fxml/1" fx:controller="sample.MainController">
   <children>
      <HBox spacing="5.0">
         <children>
            <TextField fx:id="textField" editable="false" HBox.hgrow="ALWAYS" />
            <Button mnemonicParsing="false" text="Refresh" onAction="#handleRefreshButton"/>
         </children>
      </HBox>
      <HBox fx:id="childContainer">
         <fx:include fx:id="childView" source="child.fxml" />
      </HBox>
   </children>
</VBox>

分别是两个控制器。

public class ChildController {

    @FXML
    private TextField textField;

    private Consumer<String> consumer;

    public void addConsumer(Consumer<String> consumer) {
        this.consumer = consumer;
    }

    @FXML
    private void handleSendButton(ActionEvent event) {
        if(consumer == null) {
            return;
        }

        consumer.accept(textField.getText());
    }

}

在此处,按“刷新”按钮会重新加载插入的视图。

public class MainController {
    @FXML
    private TextField textField;

    @FXML
    private HBox childContainer;

    @FXML
    private ChildController childViewController;

    @FXML
    private void initialize() {
        childViewController.addConsumer(textField::setText);
    }

    @FXML
    private void handleRefreshButton(ActionEvent event) {
        try {
            textField.setText("");

            FXMLLoader loader = new FXMLLoader(getClass().getResource("child.fxml"));
            Parent parent = loader.load();

            childViewController = loader.getController();
            childViewController.addConsumer(textField::setText);

            childContainer.getChildren().setAll(parent);
        }
        catch (IOException e) {
            e.printStackTrace();
        }
    }
}