成绩单分析项目:树形结构必修课程与学生成绩单对比及JavaFX TableColumn适配数据类型选型
成绩单分析项目:树形结构必修课程与学生成绩单对比及JavaFX TableColumn适配数据类型选型
看起来你遇到的核心矛盾是树形的要求结构和JavaFX表格扁平化/结构化展示之间的适配问题,我之前做过类似的学业评估系统,给你几个实际可行的方向:
一、适配JavaFX表格的核心数据类型:分层DTO组合方案
JavaFX的TableColumn最适合绑定结构化、可扁平化映射的数据对象,直接把树形Node丢给表格肯定会踩坑,建议用「顶层汇总DTO + 子项明细DTO」的组合,完全贴合你的评估逻辑和表格展示需求:
1. 顶层DTO:RequirementGroupSummary(替代/增强你的GroupEvaluation)
对应你原来的GroupEvaluation,但更适配UI展示:
public class RequirementGroupSummary { private String groupName; // 比如"CSCore"、"MathAndStatsCore" private boolean isGroupSatisfied; // 整个组是否满足要求 private List<String> completedSingleCourses; // 组内已完成的单门必修课程 private List<String> incompleteSingleCourses; // 组内未完成的单门必修课程 private List<ChoiceRequirementDetail> choiceRequirements; // 组内的分支要求(exactlyOneOf/atLeastOneOf/allOf) // 构造器、Getter、Setter、toString }
2. 子项明细DTO:ChoiceRequirementDetail(优化你的ChoicePick)
专门用来记录分支要求的完成情况,比原来的ChoicePick更清晰:
public class ChoiceRequirementDetail { private String requirementType; // 分支类型:"exactlyOneOf"/"atLeastOneOf"/"allOf" private String requirementLabel; // 方便展示的描述,比如"Exactly one of MATH1003/MATH1053" private List<String> allOptions; // 该分支下的所有可选课程/子要求 private List<String> studentSatisfiedBy; // 学生用来满足该要求的课程(比如exactlyOneOf就是选的那一门) private boolean isSatisfied; // 该分支要求是否已满足 // 构造器、Getter、Setter、toString }
二、树形结构到UI数据的解析优化思路
你现在卡的点应该是如何把树形Node转换成上面的DTO,核心是写一个递归的评估解析函数,遍历树形要求的同时,同步统计完成情况并填充DTO:
核心递归逻辑伪代码
// 传入单个要求节点 + 学生已修课程集合,返回该节点的评估结果 private RequirementItemEvaluation evaluateNode(Node node, Set<String> studentCourses) { boolean isSatisfied = false; List<String> satisfiedBy = new ArrayList<>(); switch (node.getType()) { case COURSE: // 单门课程的评估 isSatisfied = studentCourses.contains(node.getCourseCode()); if (isSatisfied) satisfiedBy.add(node.getCourseCode()); break; case EXACTLY_ONE_OF: // 多选一的评估:统计学生满足的子节点数量是否为1 List<RequirementItemEvaluation> childResults = node.getChildren().stream() .map(child -> evaluateNode(child, studentCourses)) .filter(RequirementItemEvaluation::isSatisfied) .toList(); isSatisfied = childResults.size() == 1; childResults.forEach(res -> satisfiedBy.addAll(res.getSatisfiedBy())); break; case AT_LEAST_ONE_OF: // 至少选一的评估:统计学生满足的子节点数量是否≥1 List<RequirementItemEvaluation> childResults = node.getChildren().stream() .map(child -> evaluateNode(child, studentCourses)) .filter(RequirementItemEvaluation::isSatisfied) .toList(); isSatisfied = !childResults.isEmpty(); childResults.forEach(res -> satisfiedBy.addAll(res.getSatisfiedBy())); break; case ALL_OF: // 必须全选的评估:所有子节点是否都满足 List<RequirementItemEvaluation> childResults = node.getChildren().stream() .map(child -> evaluateNode(child, studentCourses)) .toList(); isSatisfied = childResults.stream().allMatch(RequirementItemEvaluation::isSatisfied); childResults.forEach(res -> satisfiedBy.addAll(res.getSatisfiedBy())); break; } return new RequirementItemEvaluation(isSatisfied, satisfiedBy); } // 辅助类:存储单个节点的评估结果 private static class RequirementItemEvaluation { private boolean isSatisfied; private List<String> satisfiedBy; // 构造器、Getter }
解析流程
- 遍历你的
groupsMap(比如CSCore、MathAndStatsCore) - 对每个组的根节点列表,逐个调用上面的递归函数
- 把评估结果分类填充到
RequirementGroupSummary中:- 单门课程:直接分到
completedSingleCourses或incompleteSingleCourses - 分支要求:封装成
ChoiceRequirementDetail加入choiceRequirements
- 单门课程:直接分到
三、JavaFX表格展示的两种可选方案
根据你的UI需求,有两种不同的表格展示方式:
1. 组级汇总表(适合概览)
用普通TableView,一行对应一个要求组:
- 绑定
groupName到文本列 - 绑定
isGroupSatisfied到CheckBoxTableCell(直观展示是否满足) completedSingleCourses/incompleteSingleCourses可以用自定义TableCell,把List拼接成逗号分隔的字符串(比如"CS1073, CS1083")choiceRequirements可以用展开式单元格(点击后弹出小窗口展示所有分支要求的详情)
2. 要求项明细表格(适合精细化查看)
如果需要展示每个具体要求(单门课/分支)的完成情况,可以用TreeTableView(JavaFX自带的树状表格):
- 根节点:要求组(CSCore、MathAndStatsCore)
- 子节点:组内的每个要求(单门课/分支要求)
- 直接把
RequirementGroupSummary和ChoiceRequirementDetail转换成TreeItem,绑定到TreeTableColumn即可,完全贴合你的原始树形要求结构
四、对现有代码结构的小优化建议
- 业务层与UI层解耦:你的
GroupEvaluation可以作为业务层的评估结果对象,不要直接给UI层用,UI层只用上面的DTO,以后改UI展示逻辑不会影响业务评估代码 - 预生成要求描述标签:在解析树形结构的时候,提前把分支要求转换成用户友好的描述(比如把
{"exactlyOneOf": ["MATH1003", "MATH1053"]}转换成"Exactly one of MATH1003/MATH1053"),表格展示的时候直接用,不用在UI层再处理 - 缓存学生已修课程集合:把学生的所有已修课程转成
HashSet,查是否包含的时间复杂度是O(1),比遍历List快很多
内容来源于stack exchange
相关产品推荐
相关产品推荐

