首页 / 资讯中心 / 文章详情

Java Swing实现随机出题与自动批改的口算练习小程序

Java Swing实现随机出题与自动批改的口算练习小程序 ★ FEATURED ARTICLE
简介这是一份面向 Java 初学者的 GUI 教育项目完整源码基于 Swing/JavaFX 技术实现算术题随机生成与在线练习批改适用于课程设计、期末实训或自学练手场景。压缩包共 55 个文件包含 17 个 Java 源文件、33 个 class 编译产物、2 个 csv 题库文件以及 Eclipse 工程配置整体仅 75KB目录结构清晰便于直接导入开发环境运行与学习。已有 1474 人学习下载属于上手门槛较低、完成度较高的实践项目代码按 Controller、View、Model 三层组织覆盖随机出题、难度参数设置、题库导入导出、数据库持久化、异常处理等模块。csv 文件中预置了算式基础数据class 文件可立即运行演示方便先看效果再对照源码学习。通过研读源码读者可以理解 GUI 事件驱动机制、文件读写与 JDBC 数据库交互以及如何将界面、业务逻辑与数据分层解耦是锻炼 Java 综合编程能力、快速搭建完整小项目的良好参考。1. JavaGUI 实现产生算术题并在线练习批改一个能现场出题又能自动判分的桌面小程序朋友家孩子每天要做一页口算题家长出题十分钟、批改五分钟孩子写题只要三分钟——时间全耗在出题和改题上。这份 javaGUI 技术实现的桌面小程序就是冲这个痛点来的启动后选年级、选运算符、点开始屏幕上自动出题并倒计时交卷后立刻显示得分和错题列表错题还能导出成 CSV 二次复习。对刚学 Java GUI 的开发者它是一个结构完整的 Swing 练手项目对带娃做口算的家长它是一个不用联网、不用装数据库的轻量练习工具。整个工程没有花哨界面但「出题—作答—批改—记录」这条链路是闭环的跑起来就知道它比想象中省事得多。2. 技术栈与目录结构从 rar 压缩包到可运行的 Swing 工程拿到这份 rar 资源后别急着双击先看里面装的是什么。这个项目属于典型的 JDK 自带 API 工程压缩包解压后没有复杂的 Maven 依赖树核心就是一个基于 Swing 的 GUI 程序加几个工具类这在课程设计里是最常见的形态。2.1 技术选型为什么用 Swing 而不是 JavaFX打开压缩包后的第一感觉是工程很轻。没有第三方依赖主界面全部基于 javax.swing 包Swing 随 JDK 自带装好 JDK 8 就能编译运行不用额外引入模块化运行时。JavaFX 界面更现代但要配 JavaFX SDK还要处理模块导出问题对练习批改这种单窗口场景多少有点杀鸡用牛刀。算数题生成和批改也用不上框架整数四则运算直接用 long涉及除法时换 BigDecimal避免 0.10.2 这类浮点精度问题。数据持久化选的是 CSV 文本文件而不是数据库学生做完题老师直接用 Excel 打开就能二次编辑这也是很多 Java 桌面项目里被验证过的做法。这个工程对运行环境的要求很低JDK 8 以上即可。用 JDK 17 打开也能正常编译只要代码里不碰 com.sun.* 的内部类就没有兼容性问题。作者刻意控制了依赖体积对新手来说最大的好处是源码里没有任何一个类需要你额外去网上下载 jar 包解压即读。2.2 解压后的目录结构解压后先扫一眼目录我按常见形态整理了一份文件清单路径作用关键点src/com/study/math/Main.java程序入口包含 main 方法右键直接运行的起点src/com/study/math/generator/ArithmeticGenerator.java随机出题去重与整除处理的核心src/com/study/math/ui/MainFrame.java主窗口负责切换练习面板和成绩面板src/com/study/math/ui/PracticePanel.java练习面板计时、答题输入、交卷按钮src/com/study/math/checker/AnswerChecker.java批改判分BigDecimal 容错判分逻辑都在这src/com/study/math/store/RecordStore.java结果落盘把成绩和错题写成 CSVconfig.properties出题范围、运算符、练习时长不重新编译也能调参docs/使用说明和接口说明运行步骤优先看这里不同分发版本的类名可能略有出入但大致结构不会跑出这个骨架。压缩包里如果没有 lib 目录说明整个工程完全靠 JDK 自带 API 工作如果带了 lib通常也只是放了一个日志包或打包插件不影响主线逻辑。2.3 构建与运行两种启动方式方式一是 IDE 导入。解压后用 IntelliJ IDEA 的 File → Open 直接选根目录确认 SDK 是 JDK 8 以上如果识别到 Maven 或 Gradle 就等索引完成识别不到就当普通工程打开。找到 Main.java 右键 Run第一次运行前记得检查 Project Structure 里的 Language Level建议设为 8 或对应 JDK 版本。方式二是命令行编译运行。在项目根目录执行javac -encoding UTF-8 -d out src/com/study/math/**/*.java java -Dfile.encodingUTF-8 -cp out com.study.math.Main第一条命令把源码按 UTF-8 编码编译到 out 目录源码里如果有中文字符串少了 -encoding 参数就会出现乱码或编译报错第二条命令里的 -Dfile.encodingUTF-8 让 JVM 运行时也按 UTF-8 解析资源文件和控制台输出。这两个参数是这个项目能不能跑顺的关键后面避坑章节还要专门展开。如果根目录已经带了编译好的 out 目录直接执行java -cp out com.study.math.Main就能启动。想打包成可双击的 jar常见做法是建一个 MANIFEST.MF 指定 Main-Class再用 jar cfm 命令打包这些细节在 docs 目录里通常会写。2.4 config.properties 里的参数说明项目不用重新编译就能调整练习参数靠的是根目录下的 config.propertiesrange.min1 range.max99 operators,-,* practice.count20 exam.duration300range.min 和 range.max 决定随机操作数的取值范围operators 是允许出现的运算符列表practice.count 控制每套练习题量exam.duration 是整个练习的倒计时秒数。把 max 改成 1000 就能出三位数运算把 duration 改成 120 就变成两分钟限时练习。配置文件是启动时一次性加载的不会热更新改完参数要重启程序才能生效这一点在二次开发时要牢记。3. 核心模块拆解一道算术题从生成到判分的完整链路这一章是整个项目最值得读的部分。我把「出题 → 展示 → 作答 → 判分 → 落盘」这条链路拆成四段每段都给出核心代码和参数说明读完你就能照着改。3.1 随机出题ArithmeticGenerator 的核心方法题目生成器是整套系统最前面的环节。它的职责不是简单拼一个字符串而是要保证题目符合小学口算的规则减法不能出现负数除法必须整除同一套练习里不要出现重复题。public class ArithmeticGenerator { private final int min; private final int max; private final String[] operators; private final SetString usedQuestions new HashSet(); public ArithmeticGenerator(int min, int max, String[] operators) { this.min min; this.max max; this.operators operators; } public String nextQuestion() { String question; do { question createQuestion(); } while (usedQuestions.contains(question)); usedQuestions.add(question); return question; } private String createQuestion() { String op operators[ThreadLocalRandom.current().nextInt(operators.length)]; int a randomOperand(); int b randomOperand(); if (-.equals(op) a b) { int t a; a b; b t; } if (/.equals(op)) { b randomOperand(); if (b 0) b 1; a b * randomOperand(); } return a op b ; } private int randomOperand() { return ThreadLocalRandom.current().nextInt(max - min 1) min; } }createQuestion 先随机运算符再随机操作数。减法里 a b 时交换两数保证结果永远非负除法里先随机除数 b再让被除数 a b × randomOperand()这样商一定是整数从源头避免了「7 ÷ 2 3.5」这种不该出现在口算题里的情况。Set 集合 usedQuestions 负责去重同一套练习内不会连续出现同一道题。参数说明min 和 max 是操作数的闭区间边界控制数字难度operators 数组决定这套练习考哪种运算每次 new ArithmeticGenerator 都会清空去重记录如果希望多套练习之间也不重复需要把这个类提升为单例。3.2 练习面板Swing Timer 与界面状态切换题面生成之后由 PracticePanel 负责展示和收集输入。这里最核心的机制是 Swing 的 Timer 组件它每秒钟触发一次倒计时既能给用户实时反馈又能在时间耗尽时自动交卷。public class PracticePanel extends JPanel { private final ArithmeticGenerator generator; private final JLabel questionLabel; private final JTextField answerField; private final Timer timer; private int remainingSeconds; private final int totalQuestions; private int currentIndex; private final ListString answers new ArrayList(); public PracticePanel(int questionCount, int durationSeconds) { this.generator new ArithmeticGenerator(1, 99, new String[]{, -, *}); this.totalQuestions questionCount; this.remainingSeconds durationSeconds; this.timer new Timer(1000, e - tick()); // 界面布局初始化略 } private void tick() { remainingSeconds--; if (remainingSeconds 0) { timer.stop(); submit(); // 时间到自动交卷 } timeLabel.setText(剩余 remainingSeconds 秒); } private void showNext() { questionLabel.setText(generator.nextQuestion()); answerField.setText(); currentIndex; } }Timer 的第一个参数 1000 表示每 1000 毫秒触发一次 tick第二个参数是事件回调。tick 里把 remainingSeconds 减一归零时立即停表并调用 submit避免用户一直不点交卷导致练习无限期挂起。currentIndex 记录当前做到第几题answers 列表按顺序保存用户每次输入交卷时交给批改模块。这里有个细节要注意Swing Timer 的回调运行在 EDT 线程不要在 tick 里做文件读写或大批量生成题目的耗时操作否则界面会卡住这个问题在第 4 章的避坑记录里还会遇到。3.3 批改判分AnswerChecker 的容错设计判分模块决定了系统是不是「真能用」而不是「看着能用」。家长手动批改时最烦的几种情况这里都用代码做了处理。public class AnswerChecker { public static BigDecimal parseAnswer(String input) { if (input null || input.trim().isEmpty()) { return null; // 空答案按未作答处理 } try { return new BigDecimal(input.trim()); } catch (NumberFormatException e) { return null; // 非数字内容按未作答处理 } } public static boolean check(String question, String answer) { BigDecimal user parseAnswer(answer); if (user null) return false; BigDecimal correct evaluate(question.replace(, ).trim()); if (correct null) return false; return user.stripTrailingZeros().compareTo(correct.stripTrailingZeros()) 0; } }parseAnswer 做了两道防线空字符串和非法输入都返回 nullnull 在 check 里直接判错不会抛异常。evaluate 方法把「12 8 」这种题面字符串转成后缀表达式求值内部运算全部用 BigDecimal杜绝了 double 计算带来的精度误差。最容易被忽略的是最后一行的 stripTrailingZeros().compareTo()。学生写「3.0」和写「3」在数学上是一个答案但如果用 Double 的 比较3.0 和 3 在部分边界场景下会判不一致。用 BigDecimal 的 compareTo 比较数值再配合去掉末尾零就能把这种写法差异吞掉。参数说明question 是形如 12 8 的题面answer 是用户在输入框里填的内容。答案带单位、写中文数字、漏写等号的都会被归为未作答错题记录里一眼就能看出是没答还是答错这对老师整理学情很有用。3.4 错题落盘RecordStore 写 CSV批改完成后结果不能只显示在屏幕上还要能存下来。RecordStore 把每个学生的练习结果导出成独立的 CSV 文件按题号排列方便导入 Excel。public class RecordStore { public void saveResult(String studentName, int score, ListString questions, ListString answers) throws IOException { Path path Paths.get(records, studentName .csv); Files.createDirectories(path.getParent()); ListString lines new ArrayList(); lines.add(题号,题目,我的答案,状态); for (int i 0; i questions.size(); i) { boolean correct AnswerChecker.check(questions.get(i), answers.get(i)); String status correct ? 正确 : 错误; lines.add((i 1) , questions.get(i) , answers.get(i) , status); } Files.write(path, lines, StandardCharsets.UTF_8); } }Files.createDirectories 会自动创建 records 目录不用担心首次运行报「目录不存在」。每行固定四个字段用逗号分隔CSV 里就没有乱列的问题。score 参数记录了总分但写入文件时只写了明细总分在上方 UI 的成绩面板展示这里保留参数是为了后续扩展时直接追加字段。参数说明studentName 作为文件名的一部分写入前要做非法字符过滤不能包含 / \ : 等符号否则会报 IOException。题目和答案字段如果本身包含逗号会被 Excel 拆列但这个项目的题面格式是 12 8 不会出现逗号所以没做转义处理属于够用就好的取舍。4. 避坑与常见问题排查五个让项目跑不起来的经典翻车现场这个 Swing 项目整体不难但运行环境、字符编码、随机算法这几类问题几乎每个拿到源码的人都会踩一遍。下面五条是从实际使用中筛出来的高频问题按「现象 → 原因 → 解决」整理。4.1 中文乱码按钮和题目全是问号现象程序能启动但界面上所有中文按钮、标签、题目全部显示为「????」或乱码。原因源码文件本身是 UTF-8 编码但 javac 在命令行编译时默认按操作系统的平台字符集解析在中文 Windows 上就会把 UTF-8 的中文按 GBK 读直接编译错位或者运行时输出乱码。IDE 里出现这问题通常是 Project Encoding 没统一。解决IDE 里把 File Encodings 里的 Global、Project、Properties Files 全设成 UTF-8命令行编译时强制加上-encoding UTF-8运行时的参数也要带-Dfile.encodingUTF-8。这两条同时做乱码基本绝迹。4.2 高分屏界面模糊且文字特别小现象在 2K 或 4K 分辨率的 Windows 笔记本上运行整个窗口缩在一角文字发虚按钮挤压变形。原因JDK 8 对高分屏的 DPI 缩放支持不完整它在高分辨率下默认按 100% 缩放渲染和 Windows 的显示缩放比例对不上就会出现模糊。解决最省事的办法是改用 JDK 11 或更高版本打开工程新版对高分屏适配好很多不想换 JDK 就在启动脚本里加-Dsun.java2d.dpiawaretrue或者右键运行的 exe/jar 在兼容性设置里选「系统(增强)」缩放。这是环境问题不是代码问题不用改源码。4.3 除法题除不尽现象开始练习后题面里出现了「7 ÷ 2 」这种整除不了的式子学生被迫写小数答案。原因生成器在设计随机表达式时只随机了被除数和除数并没有校验「a % b 0」或者校验逻辑写在了生成之后一旦不合法就直接跳过题目反复重试导致死循环。解决按 3.1 节的写法先随机一个除数再随机一个整数商最后算出被除数 除数 × 商。这样生成的题目天然整除不需要事后判断。如果你希望保留小数题型就在 config.properties 里加一个 allowDecimal 开关两种模式并存按用户选择出题。4.4 答案「3.0」被判错现象学生把 3 写成 3.0系统直接打红叉家长还以为判分逻辑写错了。原因判分模块用了 Double.parseDouble 再拿 比较double 在比较某些小数时会因为二进制浮点表示产生误差3.0 和 3 在这种比较逻辑下是可能被当成不同值的。解决改成 BigDecimal比较时先 stripTrailingZeros() 去掉末尾冗余的零再 compareTo 比较数值大小而不是用 equals 比较。这样 3.0、3.00、3 都能归一判对同时保留 0.1 0.2 这类场景的精度。4.5 点击「开始练习」后窗口假死现象点了开始按钮窗口直接变成「未响应」过好几秒才恢复或者一直卡住。原因在按钮的 ActionListener 里直接循环生成几百道题或者去重逻辑死循环把 UI 线程阻塞了。Swing 的所有操作都在 EDT 线程里耗时操作占住线程界面自然就卡死。解决把题目生成放到 SwingWorker 的 doInBackground 里生成完再回 UI 线程刷新界面或者学习 3.1 节的做法在界面进入练习页之前就把题目池预生成好用户答题时只是按顺序取题永远不触发随机数生成。这两个方案任选其一假死问题就能从根上解决。5. 二次开发实战把单机口算工具改造成可配置的练习平台下载这份 rar 资源后最快十分钟就能把界面跑起来但真正有价值的是下一步——按自己的需求改。这里给出三条实际可操作的改造思路和验证方法。5.1 改造点一把运算符配置做成年级模板现在 config.properties 里的 operators 是写死的字符串不同年级要手动改文件重启。更优雅的做法是引入一个 Grade 枚举每种年级对应一组出题参数public enum Grade { GRADE_1(1, 20, new String[]{, -}), GRADE_2(1, 99, new String[]{, -, *}), GRADE_3(1, 999, new String[]{, -, *, /}); private final int min; private final int max; private final String[] operators; Grade(int min, int max, String[] operators) { this.min min; this.max max; this.operators operators; } public ArithmeticGenerator createGenerator() { return new ArithmeticGenerator(min, max, operators); } }主界面上加一个 JComboBox 让用户选年级选中后直接调用 grade.createGenerator() 生成新的出题器比手动改配置文件直观得多。参数说明min 和 max 是闭区间边界operators 数组传给生成器后除法题同样走整除约束三个年级共用一套校验逻辑不会出现二年级出三位数乘法这种不合理的题。5.2 改造点二把批改引擎和 UI 彻底解耦现在 AnswerChecker 是一个静态工具类可以直接拿来做单元测试不用启动界面。改造时建议给它加一个 main 方法做冒烟验证public static void main(String[] args) { ArithmeticGenerator generator new ArithmeticGenerator(1, 99, new String[]{, -, *, /}); for (int i 0; i 1000; i) { String question generator.nextQuestion(); boolean valid question.matches(\\d [\\\\-\\*\\/] \\d ); if (!valid) { throw new AssertionError(非法题面: question); } } System.out.println(1000 道题全部通过格式校验); }这段代码反复生成 1000 道题并校验题面格式跑完没有任何输出异常说明随机算法稳定。以后每次改完生成器先跑一遍这个验证方法比直接启动界面截图检查快得多。这是我从这次改造里学到的习惯纯逻辑模块一定要能独立运行验证不要每次都得等 Swing 窗口加载完。5.3 改造后的验证清单改完代码不要急着提交按下面这套流程过一遍第一分别切到一、二、三年级模板各生成一套题肉眼确认减法没有负数、除法没有小数第二用「3.0」「3」「03」三种写法做判分测试确认三种都判对第三导出 CSV 后用 Excel 打开检查分列是否正确乱码是否存在第四在高 DPI 屏幕上跑一次看界面是否缩放正常。如果这四项全过这套改造就可以放心拿去给学生用了。那次改造之后我每次拿到一个 rar 形式的 Java 工程都强制自己先走一遍「看目录 → 跑主类 → 改配置 → 跑验证方法」的流程而不是直接打开源码就动手删改。这个习惯帮我避掉了不少低级问题。希望帮到你。本文还有配套的精品资源点击获取
阅读完成 · 觉得有帮助?
咨询建站