天气项目中从其他控制器接收数据后无刷新更新场景的方法
Hey there! Let's figure out how to get your selected cities from the modal EnterCityDocument window into the main ListView without reloading the scene—JavaFX has some great built-in tools for this, so let's break down two straightforward approaches:
Approach 1: Use a Callback Interface (Most Explicit)
This method lets you define a clear contract for passing data between controllers. We'll create a callback interface that the MainController implements, then pass that implementation to the modal controller. When the user clicks "Select", the modal triggers the callback to send the selected cities back.
First, define the callback interface (you can put this in its own file or inside one of the controllers):
public interface CitySelectionCallback { void onCitiesSelected(List<String> selectedCities); }
Next, update your MainController to implement this interface, and pass itself to the modal when opening it:
import javafx.collections.FXCollections; import javafx.collections.ObservableList; import javafx.event.ActionEvent; 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; import java.io.IOException; import java.util.List; public class MainController implements CitySelectionCallback { @FXML private ListView<String> cityListView; // ObservableList automatically updates the UI when modified private ObservableList<String> cityList = FXCollections.observableArrayList(); @FXML public void initialize() { // Bind the ListView to our ObservableList cityListView.setItems(cityList); } @FXML private void onAddButtonClicked(ActionEvent event) { try { FXMLLoader loader = new FXMLLoader(getClass().getResource("EnterCityDocument.fxml")); Parent modalRoot = loader.load(); EnterCityDocumentController modalController = loader.getController(); // Pass the callback implementation to the modal controller modalController.setSelectionCallback(this); // Set up and show the modal window Stage modalStage = new Stage(); modalStage.initModality(Modality.APPLICATION_MODAL); modalStage.initOwner(((javafx.scene.Node) event.getSource()).getScene().getWindow()); modalStage.setScene(new Scene(modalRoot)); modalStage.showAndWait(); } catch (IOException e) { e.printStackTrace(); } } @Override public void onCitiesSelected(List<String> selectedCities) { // Add the selected cities to our ObservableList—UI updates automatically! cityList.addAll(selectedCities); } }
Now update the EnterCityDocumentController to use the callback:
import javafx.fxml.FXML; import javafx.scene.control.ListView; import javafx.stage.Stage; import java.util.List; public class EnterCityDocumentController { @FXML private ListView<String> modalCityListView; private CitySelectionCallback selectionCallback; // Method to set the callback from the main controller public void setSelectionCallback(CitySelectionCallback callback) { this.selectionCallback = callback; } @FXML private void onSelectButtonClicked() { List<String> selectedCities = modalCityListView.getSelectionModel().getSelectedItems(); if (selectionCallback != null && !selectedCities.isEmpty()) { // Trigger the callback to send data back to MainController selectionCallback.onCitiesSelected(selectedCities); // Close the modal window ((Stage) modalCityListView.getScene().getWindow()).close(); } } }
Approach 2: Share an ObservableList (More Concise)
If you don't need the extra structure of a callback, you can directly pass the MainController's ObservableList to the modal controller. Since the ListView is bound to this list, any changes will immediately reflect in the UI.
Modify the onAddButtonClicked method in MainController:
@FXML private void onAddButtonClicked(ActionEvent event) { try { FXMLLoader loader = new FXMLLoader(getClass().getResource("EnterCityDocument.fxml")); Parent modalRoot = loader.load(); EnterCityDocumentController modalController = loader.getController(); // Pass the main's ObservableList directly to the modal modalController.setMainCityList(cityList); Stage modalStage = new Stage(); modalStage.initModality(Modality.APPLICATION_MODAL); modalStage.initOwner(((javafx.scene.Node) event.getSource()).getScene().getWindow()); modalStage.setScene(new Scene(modalRoot)); modalStage.showAndWait(); } catch (IOException e) { e.printStackTrace(); } }
Then update EnterCityDocumentController to use the shared list:
import javafx.collections.ObservableList; import javafx.fxml.FXML; import javafx.scene.control.ListView; import javafx.stage.Stage; import java.util.List; public class EnterCityDocumentController { @FXML private ListView<String> modalCityListView; private ObservableList<String> mainCityList; public void setMainCityList(ObservableList<String> mainCityList) { this.mainCityList = mainCityList; } @FXML private void onSelectButtonClicked() { List<String> selectedCities = modalCityListView.getSelectionModel().getSelectedItems(); if (mainCityList != null && !selectedCities.isEmpty()) { // Add directly to the shared ObservableList—UI updates instantly mainCityList.addAll(selectedCities); ((Stage) modalCityListView.getScene().getWindow()).close(); } } }
Key Note
The magic here is JavaFX's ObservableList—it's designed to notify bound UI components (like your ListView) whenever its contents change. That means you never have to manually refresh the scene or reload the FXML; updating the list is all you need to do.
内容的提问来源于stack exchange,提问作者Kian Park

