JavaFX中Introspection生成GridPane后如何获取控件值的技术问题
JavaFX反射生成GridPane并处理Dialog数据的解决方案
我来帮你搞定这个问题!你现在遇到的核心问题有两个:一是反射生成控件时没法把Etudiant的属性值填进去,二是点击OK后没法从动态创建的控件里获取值更新对象。咱们一步步来解决:
第一步:修改反射方法,保存控件与字段的映射并初始化值
首先,你的analyserChamp方法需要做两个关键改进:
- 给动态创建的控件设置初始值(从传入的
Etudiant对象中读取) - 保存每个字段与对应控件的映射,方便后续从控件中取值
我们可以通过传入一个Map参数来存储这个映射,修改后的代码如下:
import java.lang.reflect.Field; import java.util.ArrayList; import java.util.List; import java.util.Map; import javafx.scene.control.ComboBox; import javafx.scene.control.Control; import javafx.scene.control.Label; import javafx.scene.control.TextField; import javafx.scene.layout.GridPane; public class Analysateur { public static GridPane analyserChamp(Etudiant etu, Map<Field, Control> fieldControlMap) { List<String> list = new ArrayList<>(); Class<? extends Etudiant> etuClass = etu.getClass(); Field[] attributs = etuClass.getDeclaredFields(); GridPane gp = new GridPane(); int i = 0; for (Field p : attributs) { list.add(p.getName()); Label lab = new Label(p.getName()); gp.add(lab, 0, i); // 允许访问私有字段 p.setAccessible(true); try { if (!p.getName().equals("classe")) { TextField tf = new TextField(); // 给TextField设置初始值 tf.setText(p.get(etu).toString()); gp.add(tf, 1, i); fieldControlMap.put(p, tf); } else { ComboBox<String> cb = new ComboBox<>(); cb.getItems().addAll("1Bi", "2Bi", "3Bi"); // 给ComboBox选中对应的值 cb.setValue(p.get(etu).toString()); gp.add(cb, 1, i); fieldControlMap.put(p, cb); } } catch (IllegalAccessException e) { e.printStackTrace(); } i++; } return gp; } }
第二步:修改Dialog调用代码,处理控件取值与对象更新
接下来,在双击事件的处理逻辑中,我们需要创建映射存储字段与控件的关联,然后在点击OK按钮时遍历映射,把控件的新值设置回Etudiant对象:
import java.util.HashMap; import java.util.Map; import javafx.scene.control.ButtonType; import javafx.scene.control.Dialog; import javafx.scene.control.TableView; import javafx.scene.layout.GridPane; // 双击TableView行的事件处理代码 if (e.getClickCount() == 2) { Dialog<Etudiant> dialog = new Dialog<>(); Etudiant selectedEtudiant = tableViewEtudiant.getSelectionModel().getSelectedItems().get(0); if (selectedEtudiant != null) { dialog.setTitle("Editor"); dialog.setHeaderText("Update Student Information"); // 创建映射保存字段与控件的对应关系 Map<Field, Control> fieldControlMap = new HashMap<>(); GridPane contentGrid = Analysateur.analyserChamp(selectedEtudiant, fieldControlMap); dialog.getDialogPane().setContent(contentGrid); ButtonType buttonCancel = new ButtonType("Cancel", ButtonData.CANCEL_CLOSE); ButtonType buttonOk = new ButtonType("Ok", ButtonData.OK_DONE); dialog.getDialogPane().getButtonTypes().addAll(buttonOk, buttonCancel); // 处理OK按钮的逻辑:更新Etudiant对象 dialog.setResultConverter(dialogButton -> { if (dialogButton == buttonOk) { for (Map.Entry<Field, Control> entry : fieldControlMap.entrySet()) { Field field = entry.getKey(); Control control = entry.getValue(); field.setAccessible(true); try { if (control instanceof TextField) { TextField tf = (TextField) control; // 若字段不是String类型,需要额外做类型转换(比如转int、Date等) field.set(selectedEtudiant, tf.getText()); } else if (control instanceof ComboBox) { ComboBox<String> cb = (ComboBox<String>) control; field.set(selectedEtudiant, cb.getValue()); } } catch (IllegalAccessException ex) { ex.printStackTrace(); } } return selectedEtudiant; } return null; }); // 显示Dialog并处理更新后的对象 dialog.showAndWait().ifPresent(updatedEtudiant -> { // 这里可以更新TableView数据或保存到Gson文件 tableViewEtudiant.refresh(); // 编写你的Gson文件更新逻辑 }); } }
关键注意点
- 私有字段访问:因为
Etudiant的字段通常是private修饰的,必须调用field.setAccessible(true)才能直接读写字段值。 - 类型转换:上面的代码假设所有字段都是
String类型,如果有int、Date等其他类型,需要在设置值时添加对应的类型转换逻辑。 - ResultConverter:使用Dialog的
setResultConverter处理按钮点击逻辑,比直接在showAndWait后处理更清晰,还能直接返回更新后的对象。
这样修改后,你就能实现双击TableView行弹出带初始值的修改Dialog,点击OK后自动把控件的新值更新回Etudiant对象啦!
内容的提问来源于stack exchange,提问作者Florian Genicq
相关产品推荐
相关产品推荐

