如何在从另一个类/控制器接收数据后更新场景而不刷新场景

时间:2018-03-03 16:24:45

标签: javafx

我正在开发一个包含Main.fxml,MainController.java,EnterCityDocument.fxml和EnterCityDocumentController.java的个人天气项目。

  1. Main.fxml:包含一个边框窗格,其中心有一个显示城市名称的ListView。它还有一个“添加”按钮,用于打开一个新的模态窗口(EnterCityDocument.fxml),以便将一个城市添加到其ListView。

  2. EnterCityDocument.fxml:包含一个包含城市名称的listView和一个“选择”按钮,用于选择用户想要在Main.fxml中显示的城市。当用户单击“选择”按钮时,模式窗口(EnterCityDocument.fxml)关闭,Main.fxml继续运行。

  3. MainController.java是EnterCityDocumentController.java的父类。

  4. 我一直在寻找将子类(EnterCityDocumentController.java)中的数据传递给父类(MainController.java)并找到一种方法来实现它,但我发现的所有方法都需要刷新每当用户在EnterCityDocumentController.java中选择一个城市时,MainController.java类。

    当将新城市添加到Main.fxml的listView中时,有没有办法更新Main.fxml而不刷新主场景?

    希望我的问题足够明确。如果您需要进一步的解释/代码,请告诉我!

1 个答案:

答案 0 :(得分:0)

您需要做的就是从对话框中安排新城市添加到列表视图的后备列表中。由于您使用 @Override public int getItemCount() { return 5; // returning static no of items } ,这非常简单:只需在showAndWait()类中定义一个返回新城市的方法,然后在EnterCityDocumentController之后调用它:

showAndWait()

然后在主控制器中:

public class EnterCityDocumentController {

    @FXML
    private TextField cityNameField ;

    // other fields, etc...

    @FXML
    private void okButtonPressed() {
        // just close the window:
        cityNameField.getScene().getWindow().hide();
    }

    public City getUserCity() {
        return new City(cityNameField.getText());
    }
}

这是一个SSCCE:

public class MainController { @FXML private ListView<City> listView ; // handler method: @FXML public void addNewCity() throws IOException { FXMLLoader loader = new FXMLLoader(EnterCityDocumentController.class.getResource("EnterCityDocument.fxml")); Scene scene = new Scene(loader.load()); Stage stage = new Stage(); stage.setScene(scene); stage.showAndWait(); listView.getItems().add(controller.getUserCity()); } }

app/Main.fxml

<?xml version="1.0" encoding="UTF-8"?> <?import javafx.geometry.Insets?> <?import javafx.scene.control.Button?> <?import javafx.scene.control.ListView?> <?import javafx.scene.layout.BorderPane?> <BorderPane xmlns="http://javafx.com/javafx/8.0.111" xmlns:fx="http://javafx.com/fxml/1" fx:controller="app.MainController"> <center> <ListView fx:id="listView" prefHeight="200.0" prefWidth="200.0" BorderPane.alignment="CENTER" /> </center> <bottom> <Button mnemonicParsing="false" onAction="#addNewElement" text="Add..." BorderPane.alignment="CENTER"> <BorderPane.margin> <Insets bottom="2.0" left="2.0" right="2.0" top="2.0" /> </BorderPane.margin> </Button> </bottom> </BorderPane>

app/AddNewElement.fxml

<?xml version="1.0" encoding="UTF-8"?> <?import javafx.geometry.Insets?> <?import javafx.scene.control.Button?> <?import javafx.scene.control.TextField?> <?import javafx.scene.layout.ColumnConstraints?> <?import javafx.scene.layout.GridPane?> <?import javafx.scene.layout.RowConstraints?> <GridPane hgap="5.0" vgap="5.0" xmlns="http://javafx.com/javafx/8.0.111" xmlns:fx="http://javafx.com/fxml/1" fx:controller="app.AddNewElementController"> <rowConstraints> <RowConstraints /> <RowConstraints /> </rowConstraints> <columnConstraints> <ColumnConstraints halignment="CENTER" /> <ColumnConstraints halignment="CENTER" /> </columnConstraints> <children> <TextField fx:id="textField" GridPane.columnSpan="2" /> <Button defaultButton="true" mnemonicParsing="false" onAction="#ok" text="OK" GridPane.rowIndex="1" /> <Button cancelButton="true" mnemonicParsing="false" onAction="#cancel" text="Cancel" GridPane.columnIndex="1" GridPane.rowIndex="1" /> </children> <padding> <Insets bottom="5.0" left="5.0" right="5.0" top="5.0" /> </padding> </GridPane>

app/AddNewElementController.java

package app; import javafx.fxml.FXML; import javafx.scene.control.TextField; public class AddNewElementController { @FXML private TextField textField ; private boolean approved ; public boolean isApproved() { return approved ; } public String getUserText() { return isApproved() ? textField.getText() : null ; } @FXML private void cancel() { approved = false ; hide(); } @FXML private void ok() { approved = true ; hide(); } private void hide() { textField.getScene().getWindow().hide(); } }

app/MainController.java

package app; import java.io.IOException; import javafx.fxml.FXML; import javafx.fxml.FXMLLoader; import javafx.scene.Parent; import javafx.scene.Scene; import javafx.scene.control.ListView; import javafx.stage.Modality; import javafx.stage.Stage; public class MainController { @FXML private ListView<String> listView ; @FXML private void addNewElement() throws IOException { FXMLLoader loader = new FXMLLoader(AddNewElementController.class.getResource("AddNewElement.fxml")); Parent root = loader.load(); AddNewElementController controller = loader.getController(); Scene scene = new Scene(root); Stage stage = new Stage(); stage.initModality(Modality.APPLICATION_MODAL); stage.initOwner(listView.getScene().getWindow()); stage.setScene(scene); stage.showAndWait(); if (controller.isApproved()) { listView.getItems().add(controller.getUserText()); } } }

app/Main.java

另一种非常不同的方法是将listview的支持列表传递给第二个控制器。然后第二个控制器可以直接将项目添加到列表中(列表视图将像以前一样自动更新)。即使您没有使用package app; import java.io.IOException; import javafx.application.Application; import javafx.fxml.FXMLLoader; import javafx.scene.Parent; import javafx.scene.Scene; import javafx.stage.Stage; public class Main extends Application { @Override public void start(Stage primaryStage) throws IOException { FXMLLoader loader = new FXMLLoader(MainController.class.getResource("Main.fxml")); Parent root = loader.load(); Scene scene = new Scene(root); primaryStage.setScene(scene); primaryStage.show(); } public static void main(String[] args) { launch(args); } } ,也可以使用此方法(在用户关闭窗口之前,它不依赖于代码阻止)。

showAndWait()

package app;

import java.util.List;

import javafx.fxml.FXML;
import javafx.scene.control.TextField;

public class AddNewElementController {

    @FXML
    private TextField textField ;

    private List<String> itemList ;

    public void setItemList(List<String> itemList) {
        this.itemList = itemList ;
    }


    @FXML
    private void cancel() {
        hide(); 
    }

    @FXML
    private void ok() {
        itemList.add(textField.getText());
        hide();
    }

    private void hide() {
        textField.getScene().getWindow().hide();
    }
}