JavaFX:getController无法更新FXML控制器的跨控制器调用问题
解决JavaFX跨控制器调用方法不更新界面的问题
问题根源
你当前的核心问题有两个:
- 在
Rem控制器中通过FXMLLoader加载main.fxml得到的Main实例是全新创建的对象,并非界面上正在显示的那个,调用其makeTable方法只会修改新实例的数据,不会影响当前界面的TableView。 Main中的TableView列仅在初始化时加载一次静态columns变量,后续columns更新时,界面不会自动同步列的变化。
推荐解决方案:直接传递当前Main控制器实例给Rem
因为Rem是被Main动态加载到界面中的,所以可以在加载Rem时直接把当前Main的实例传递给Rem控制器,让Rem直接操作界面上的Main实例。
1. 修改Rem.java
添加Main类型的成员变量和setter方法,用于接收当前Main实例:
public class Rem implements Initializable { @FXML private Button btn; private Main mainController; @Override public void initialize(URL url, ResourceBundle rb) {} // 接收Main控制器实例的setter public void setMainController(Main mainController) { this.mainController = mainController; } @FXML private void loadTab(ActionEvent event) { try{ var rs = App.getRS("tab2"); // 调用当前界面上的Main实例的makeTable方法 mainController.makeTable(rs); }catch(Exception ex){ System.out.println(ex); } } }
2. 修改Main.java的loadRem方法
在加载Rem后,将当前Main实例传递给Rem控制器:
@FXML private void loadRem(ActionEvent event) { try{ // 清空原有Rem组件 for(int i=remPane.getChildren().size()-1;i>=0;i--){ remPane.getChildren().remove(i); } // 加载Rem的FXML FXMLLoader fxmlLoader = new FXMLLoader(getClass().getResource("rem.fxml")); Pane panel = fxmlLoader.load(); // 获取Rem控制器并传递当前Main实例 Rem remController = fxmlLoader.getController(); remController.setMainController(this); // 添加到界面 remPane.getChildren().add(panel); makeTable(App.getRS("tab1")); }catch(Exception ex){ System.out.println(ex); } }
3. 修正Main中TableView列的绑定逻辑
让TableView的列自动响应静态columns的变化:
public class Main implements Initializable { @FXML public TableView<ObservableList<String>> Tab; @FXML private VBox remPane; private static final ObservableList<TableColumn<ObservableList<String>,String>> columns = FXCollections.observableArrayList(); private static final javafx.beans.property.ListProperty<ObservableList<String>> rows = new javafx.beans.property.SimpleListProperty(); @Override public void initialize(URL url, ResourceBundle rb) { // 绑定TableView的数据源到rows Tab.itemsProperty().bind(rows); // 初始化列,并添加监听:当columns变化时自动更新TableView的列 Tab.getColumns().setAll(columns); columns.addListener((ListChangeListener.Change<? extends TableColumn<ObservableList<String>, String>> change) -> { Tab.getColumns().clear(); Tab.getColumns().addAll(columns); }); } // 保留原makeTable和setTable方法不变 public void makeTable(ResultSet rs){ try{ var rsm=rs.getMetaData(); ObservableList<TableColumn<ObservableList<String>,String>> cols=FXCollections.observableArrayList(); for(int i=0;i<rsm.getColumnCount();i++){ final int j=i; TableColumn<ObservableList<String>,String> col=new TableColumn(rsm.getColumnName(i+1)); col.setCellValueFactory(param->new SimpleStringProperty(param.getValue().get(j))); cols.add(col); } ObservableList<ObservableList<String>> arows=FXCollections.observableArrayList(); while(rs.next()){ ObservableList<String> row=FXCollections.observableArrayList(); for(int i=1;i<=rsm.getColumnCount();i++){ row.add(rs.getString(i)); } arows.add(row); } setTable(cols,arows); }catch(Exception ex){ System.out.println(ex); } } private static void setTable(ObservableList<TableColumn<ObservableList<String>,String>> c, ObservableList<ObservableList<String>> r){ columns.setAll(c); rows.set(r); } // 上面修改后的loadRem方法 @FXML private void loadRem(ActionEvent event) { try{ for(int i=remPane.getChildren().size()-1;i>=0;i--){ remPane.getChildren().remove(i); } FXMLLoader fxmlLoader = new FXMLLoader(getClass().getResource("rem.fxml")); Pane panel = fxmlLoader.load(); Rem remController = fxmlLoader.getController(); remController.setMainController(this); remPane.getChildren().add(panel); makeTable(App.getRS("tab1")); }catch(Exception ex){ System.out.println(ex); } } }
内容的提问来源于stack exchange,提问作者JavaUser
相关产品推荐
相关产品推荐

