如何使用 JavaFX 通过 window 2 中的按钮操作更新 window 1 中的 TableView

How do I update a TableView in window 1 by an action of a button in window 2 with JavaFX

从昨天开始我就一直在搜索和思考这个问题。现在大约10个小时。我已经浏览了所有与我的问题有任何相似之处的现有线程,其中 none 对我有所帮助。我已经尝试使用所谓的“回调”方法,但我仍然无法让它工作。

情况:

如何才能在创建 TableView 的新条目后立即在 tableview 中显示该条目。如何在从第二个 window(stage) 为它创建新条目时使 TableView 刷新? 基本上,我需要实现的是让一个控制器的方法被另一个不在同一个控制器中的控制器触发window。

这是TableView所在的第一阶段的控制器(“lectureHallsTableView”)。

package main.JavaFX;

import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.fxml.FXML;
import javafx.fxml.FXMLLoader;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.TableColumn;
import javafx.scene.control.TableView;
import javafx.scene.control.cell.PropertyValueFactory;
import javafx.stage.Modality;
import javafx.stage.Stage;
import main.classes.LectureHall;
import main.sqlite.DatabaseCommunicaton;

import java.io.IOException;
import java.sql.SQLException;
import java.util.ArrayList;

public class LectureHallsTabController {
    @FXML
    private TableView<LectureHall> lectureHallsTableView;
    @FXML
    private Button addNewLectureHallButton;
    @FXML
    private Button deleteLectureHallButton;

    private TableColumn<LectureHall, String> column1;
    private TableColumn<LectureHall, Integer> column2;

    ArrayList<LectureHall> lhlist = new ArrayList<>();
    DatabaseCommunicaton dbcomm = new DatabaseCommunicaton();

    public void initialize() throws SQLException {
        column1 = new TableColumn<>("Hall code");
        column2 = new TableColumn<>("Hall capacity");
        column1.setCellValueFactory(new PropertyValueFactory<>("hallCode"));
        column2.setCellValueFactory(new PropertyValueFactory<>("capacity"));
        lectureHallsTableView.getColumns().add(0, column1);
        lectureHallsTableView.getColumns().add(1, column2);
        lhlist = dbcomm.queryLectureHalls();
        lectureHallsTableView.getItems().addAll(lhlist);

        /**
         * Delete button functionality
         */
        deleteLectureHallButton.setOnAction(new EventHandler<ActionEvent>() {
            @Override
            public void handle(ActionEvent actionEvent) {
                LectureHall selectedItem = lectureHallsTableView.getSelectionModel().getSelectedItem();
                try {
                    lhlist = dbcomm.deleteLectureHall(selectedItem.getId());
                    lectureHallsTableView.getItems().clear();
                    lectureHallsTableView.getItems().addAll(lhlist);
                } catch (SQLException e) {
                    e.printStackTrace();
                }
            }
        });

    }
    /**
     * populates the tableView with all the existing database entries
     */
    public void refreshLectureHalls() throws SQLException {
        lhlist = dbcomm.queryLectureHalls();
    }

    public void openLectureHallInputWindow(ActionEvent actionEvent) {
        Stage stage = new Stage();
        Parent root = null;
        try {
            root = FXMLLoader.load(getClass().getResource("lectureHallInput.fxml"));
        } catch (IOException e) {
            e.printStackTrace();
        }

        stage.setTitle("Lecture Input");
        stage.setScene(new Scene(root));
        stage.setResizable(false);

        // Serves the purpose of the new window being imposed over the other window
        stage.initModality(Modality.APPLICATION_MODAL);

        stage.show();

    }

}

这是第二个window的控制器,可以通过它创建一个新条目:

package main.JavaFX;

import javafx.beans.value.ChangeListener;
import javafx.beans.value.ObservableValue;
import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.fxml.FXML;
import javafx.scene.control.Button;
import javafx.scene.control.TextField;
import javafx.stage.Stage;
import main.sqlite.DatabaseCommunicaton;

import java.sql.SQLException;

public class LectureHallInputController {

    @FXML
    private Button confirmButton;
    @FXML
    private Button cancelButton;
    @FXML
    private TextField hallCodeField;
    @FXML
    private TextField hallCapacityField;

    public void initialize() {

        cancelButton.setOnAction(new EventHandler<ActionEvent>() {
            @Override
            public void handle(ActionEvent actionEvent) {
                Stage stage = (Stage) cancelButton.getScene().getWindow();
                stage.close();
            }
        });
   
        confirmButton.setOnAction(new EventHandler<ActionEvent>() {
            @Override
            public void handle(ActionEvent actionEvent) {
                String hallCode = hallCodeField.getText();
                int hallCapacity = Integer.parseInt(hallCapacityField.getText());
                DatabaseCommunicaton dbcomm = new DatabaseCommunicaton();
                try {
                    dbcomm.addLectureHall(hallCode, hallCapacity);
                } catch (SQLException e) {
                    e.printStackTrace();
                }
                Stage stage = (Stage) confirmButton.getScene().getWindow();
                stage.close();
            }
        });
    }
}

我已经实施了 中详述的答案。 我所做的要点是,我创建了一个新的 class,用于“托管”我的两个 windows/stages 然后从中读取数据的 ObservableList。 由于可观察列表会自动通知我的 tableView 任何更改,通过对其进行更改(例如在我的情况下添加一个新条目),其中一个 window/stage,另一个 window 自动和立即在其 tableView 中显示更改。

这是我创建的class,这是我需要的

public class LectureHallData{
    DatabaseCommunicaton dbcomm = new DatabaseCommunicaton();

    public ObservableList<LectureHall> getLectureHallList() {
        return lectureHallList;
    }

    public ObservableList<LectureHall> lectureHallList = FXCollections.observableArrayList(lectureHall -> new Observable[]{lectureHall.codeProperty(), lectureHall.capacityProperty()});
    private ObjectProperty<LectureHall> currentLectureHall = new SimpleObjectProperty<>();

    public ObservableList<LectureHall> loadLectureHalls() throws SQLException {
        ObservableList<LectureHall> lectureHallObservableList = FXCollections.observableArrayList(dbcomm.queryLectureHalls());
        this.lectureHallList = lectureHallObservableList;
        return lectureHallObservableList;
    }

    public void refreshLectureHalls() throws SQLException {
        this.lectureHallList.clear();
        this.lectureHallList.addAll(FXCollections.observableArrayList(dbcomm.queryLectureHalls()));
    }

    public void addLectureHall(String hallCode, int hallCapacity) throws SQLException {
        dbcomm.addLectureHall(hallCode, hallCapacity);
        refreshLectureHalls();
    }

}

这是 window 的控制器,第 2 个 window 就是从中产生的

public class LectureHallsTabController {
    @FXML
    private TableView<LectureHall> lectureHallsTableView;
    @FXML
    private Button addNewLectureHallButton;
    @FXML
    private Button deleteLectureHallButton;

    private TableColumn<LectureHall, String> column1;
    private TableColumn<LectureHall, Integer> column2;

    ArrayList<LectureHall> lhlist = new ArrayList<>();
    DatabaseCommunicaton dbcomm = new DatabaseCommunicaton();
    private LectureHallData data;

    public void initialize() throws SQLException {

        initData();


    }

  public void openLectureHallInputWindow(ActionEvent actionEvent) {
        FXMLLoader loader = new FXMLLoader(getClass().getResource("lectureHallInput.fxml"));
        Stage stage = new Stage();
        Parent root = null;
        try {
            root = loader.load();
        } catch (IOException e) {
            e.printStackTrace();
        }

        LectureHallInputController lectureHallInputController = loader.getController();
        lectureHallInputController.initData(data);
        stage.setTitle("Lecture Input");
        stage.setScene(new Scene(root));
        stage.setResizable(false);

        // Serves the purpose of the new window being imposed over the other window
        stage.initModality(Modality.APPLICATION_MODAL);

        stage.show();

    }

    public void initData() throws SQLException {
        // ensure data is only set once:
        if (this.data != null) {
            throw new IllegalStateException("Data can only be initialized once");
        }
        this.data=new LectureHallData();
        column1 = new TableColumn<>("Hall code");
        column2 = new TableColumn<>("Hall capacity");
        column1.setCellValueFactory(new PropertyValueFactory<>("hallCode"));
        column2.setCellValueFactory(new PropertyValueFactory<>("capacity"));
        lectureHallsTableView.getColumns().add(0, column1);
        lectureHallsTableView.getColumns().add(1, column2);

        lectureHallsTableView.getItems().clear();
        data.loadLectureHalls();
        lectureHallsTableView.setItems(data.getLectureHallList());
    }

}

这是第二个window的控制器

public class LectureHallInputController {

    @FXML
    private Button confirmButton;
  
   ...

    private LectureHallData data;

    public void initialize() {

    ...

    confirmButton.setOnAction(new EventHandler<ActionEvent>() {
            @Override
            public void handle(ActionEvent actionEvent) {
                String hallCode = hallCodeField.getText();
                int hallCapacity = Integer.parseInt(hallCapacityField.getText());
                try {
                    data.addLectureHall(hallCode, hallCapacity);
                } catch (SQLException throwables) {
                    throwables.printStackTrace();
                }
                Stage stage = (Stage) confirmButton.getScene().getWindow();
                stage.close();
            }
        });
    }

    public void initData(LectureHallData data) {
        this.data = data;
    }

}