无FXML实现:点击按钮在Tab中加载Stage的技术求助
解决方案:把CreateScheme改成可复用UI组件而非独立Stage
嘿,这问题很常见——你现在把CreateScheme当成了一个独立的JavaFX应用(继承了Application),所以调用start()的时候会弹出新窗口。我们只需要把它重构为一个普通的UI组件类,让它返回自己的根容器,就能轻松嵌入到Tab里了,完全不用FXML。
步骤1:重构CreateScheme类
把它从Application改成普通类,移除start()和main()方法,换成一个返回Pane的方法,把原来的UI创建逻辑移进去,去掉所有和Stage、Scene相关的冗余代码:
public class CreateScheme { // 返回该UI组件的根容器 public Pane getRootPane() { Pane pane = new Pane(); // 保留你原来的所有UI创建逻辑 VBox vbox = new VBox(); VBox vbox2 = new VBox(); HBox hbox = new HBox(); HBox hbox2 = new HBox(); HBox hbox3 = new HBox(); Label label = new Label("Bewertungsschema erstellen: "); Button button = new Button("New"); TextField textField1 = new TextField(); CheckBox checkbox = new CheckBox(); Button addButton = new Button("Erstellen"); Button cancelButton = new Button("Abbrechen"); Button saveButton = new Button("Speichern"); Button addTextFieldButton = new Button("+"); TableView<Model> tableview = new TableView<Model>(); TableColumn<Model, String> table1 = new TableColumn<Model, String>("Table1"); TableColumn<Model, String> table2 = new TableColumn<Model, String>("Table2"); TableColumn<Model, String> table3 = new TableColumn<Model, String>("Table3"); TableColumn<Model, String> table4 = new TableColumn<Model, String>("Table4"); TableColumn<Model, String> table5 = new TableColumn<Model, String>("Table5"); ObservableList<Model> list = Listen.getUserList(); tableview.setItems(list); tableview.setEditable(true); tableview.getColumns().addAll(table1, table2, table4, table5, table3); table1.setCellFactory(TextFieldTableCell.<Model>forTableColumn()); table2.setCellFactory(TextFieldTableCell.<Model>forTableColumn()); table3.setCellFactory(TextFieldTableCell.<Model>forTableColumn()); table4.setCellFactory(TextFieldTableCell.<Model>forTableColumn()); table5.setCellFactory(TextFieldTableCell.<Model>forTableColumn()); textField1.setVisible(false); checkbox.setVisible(false); vbox2.setVisible(false); hbox.setSpacing(10.0); hbox.getChildren().addAll(button, textField1, checkbox); vbox.setLayoutX(10.0); vbox.setLayoutY(30.0); vbox.setSpacing(30.0); vbox.setPadding(new Insets(10.0, 20.0, 30.0, 10.0)); vbox.getChildren().addAll(label, hbox); vbox2.setLayoutX(300.0); vbox2.setLayoutY(30.0); vbox2.setSpacing(30.0); vbox2.setMaxHeight(200.0); vbox2.setPadding(new Insets(50.0, 30.0, 30.0, 30.0)); vbox2.getChildren().add(tableview); hbox2.setLayoutX(10.0); hbox2.setLayoutY(500.0); hbox2.setSpacing(20.0); hbox3.setLayoutX(10.0); hbox3.setLayoutY(550.0); hbox3.setSpacing(20.0); hbox3.getChildren().addAll(addButton, cancelButton, saveButton, addTextFieldButton); button.setOnAction(new EventHandler<ActionEvent>() { public void handle(ActionEvent e) { textField1.setVisible(true); checkbox.setVisible(true); } }); checkbox.setOnAction(new EventHandler<ActionEvent>() { public void handle(ActionEvent e) { vbox2.setVisible(true); textField1.setEditable(false); } }); addTextFieldButton.setOnAction(e -> hbox2.getChildren().add(new TextField())); addButton.setOnAction(new EventHandler<ActionEvent>() { public void handle(ActionEvent e) { //list.add(new Model(); tableview.refresh(); } }); pane.getChildren().addAll(vbox, vbox2, hbox2, hbox3); pane.getStylesheets().add("style.css"); return pane; } }
步骤2:修改Controller的点击事件逻辑
把原来弹出新Stage的代码,改成直接将CreateScheme的UI容器设置到目标Tab中:
public void changeStage() { // 实例化CreateScheme并获取它的根容器 CreateScheme cs = new CreateScheme(); Pane schemeContent = cs.getRootPane(); // 将容器设置给tab1的内容 tab1.setContent(schemeContent); // 可选:自动切换到该Tab tabPane.getSelectionModel().select(tab1); }
额外优化建议
- 如果你不需要每次点击都生成全新的UI,可以复用Controller中已声明的
CreateScheme cs = new CreateScheme();实例,不用每次都new。 - 如果需要支持多次创建独立的UI实例,保持每次
new CreateScheme()即可。
这样修改后,点击按钮就会直接在指定Tab内显示CreateScheme的所有UI内容,不会再弹出独立窗口啦!
内容的提问来源于stack exchange,提问作者dornigB
相关产品推荐
相关产品推荐

