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

时间:2021-09-14 14:02:38

I have a scene contain a hbox(root) with 2 vboxes, each vbox contain seperate fxml files and controllers. 1st vbox contains a button and textfield,and 2nd one contain a listview,So what I need is when I click the button value on textfield should be passed to listview and update without loading a new stage thats all.
Note: I found a working solution by using

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

fx:include id="v1" as vbox children

fx:包含id =“v1”作为vbox子项

in fxml and init the controllers in main controller, but sadly later if I want replace the vbox children with new fxml means, what will I do? So any simple working solutions?

在fxml中并初始化主控制器中的控制器,但遗憾的是,如果我想用新的fxml替换vbox子项,我该怎么办?那么任何简单的工作方案?

Here is my maincontroller.java

这是我的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 个解决方案

#1


0  

To make what you want, you need to have access to the controllers (the controllers themselves must be able to communicate with each other). FXMLLoader offers several options for accessing controllers. The first option is to automatically inject the fxml components included with the include in the fxml file.

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

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

In order for the controller to be injected, a field of the controller type specified in child.fxml must be declared with the name specified in fx:id with suffix Controller. And of course, annotate with @FXML.

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

public class MainController {
    @FXML
    private ChildController childViewController;

    ...
}

If you are going to be working with a dynamically changing context, you can manually create the controller and pass it on to FXMLLoader, which will initialize it by injecting the appropriate fields or simply picking up the initialized instance.

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

Here, it's important to first call FXMLLoader#load(), and then FXMLLoader#getController().

在这里,首先调用FXMLLoader#load(),然后调用FXMLLoader #getController()是很重要的。

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

ChildController controller = loader.getController();

When manually creating the controller, you must first call FXMLLoader#setController() and then FXMLLoader#load().

手动创建控制器时,必须首先调用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();

Consequently, communication between controllers is trivial and I do not think there is a need to explain.

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

UPDATE

An example of how communication is made between objects. These are the two views that use the app:

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

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>

And respectively the two controllers.

分别是两个控制器。

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());
    }

}

Here, pressing the Refresh button reloads the inserted view.

在这里,按“刷新”按钮可重新加载插入的视图。

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();
        }
    }
}

#1


0  

To make what you want, you need to have access to the controllers (the controllers themselves must be able to communicate with each other). FXMLLoader offers several options for accessing controllers. The first option is to automatically inject the fxml components included with the include in the fxml file.

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

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

In order for the controller to be injected, a field of the controller type specified in child.fxml must be declared with the name specified in fx:id with suffix Controller. And of course, annotate with @FXML.

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

public class MainController {
    @FXML
    private ChildController childViewController;

    ...
}

If you are going to be working with a dynamically changing context, you can manually create the controller and pass it on to FXMLLoader, which will initialize it by injecting the appropriate fields or simply picking up the initialized instance.

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

Here, it's important to first call FXMLLoader#load(), and then FXMLLoader#getController().

在这里,首先调用FXMLLoader#load(),然后调用FXMLLoader #getController()是很重要的。

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

ChildController controller = loader.getController();

When manually creating the controller, you must first call FXMLLoader#setController() and then FXMLLoader#load().

手动创建控制器时,必须首先调用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();

Consequently, communication between controllers is trivial and I do not think there is a need to explain.

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

UPDATE

An example of how communication is made between objects. These are the two views that use the app:

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

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>

And respectively the two controllers.

分别是两个控制器。

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());
    }

}

Here, pressing the Refresh button reloads the inserted view.

在这里,按“刷新”按钮可重新加载插入的视图。

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();
        }
    }
}