import javax.swing.*; import java.awt.*; import java.awt.event.ActionEvent; import java.util.*; import java.util.List; import java.util.regex.Pattern; import java.io.*; import java.nio.file.*; /** * MathLearningApp的方法扩展类 * 包含所有事件处理和工具方法 */ public class MathLearningAppMethods { /** * 创建样式化按钮 */ public static JButton createStyledButton(String text, Color backgroundColor) { JButton button = new JButton(text) { @Override protected void paintComponent(Graphics g) { Graphics2D g2 = (Graphics2D) g.create(); g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); // 创建渐变效果 GradientPaint gradient = new GradientPaint(0, 0, backgroundColor.brighter(), 0, getHeight(), backgroundColor.darker()); g2.setPaint(gradient); g2.fillRoundRect(0, 0, getWidth(), getHeight(), 15, 15); // 添加内阴影效果 g2.setColor(new Color(0, 0, 0, 30)); g2.drawRoundRect(1, 1, getWidth()-3, getHeight()-3, 13, 13); g2.dispose(); super.paintComponent(g); } }; button.setFont(new Font("微软雅黑", Font.BOLD, 14)); button.setForeground(Color.WHITE); button.setFocusPainted(false); button.setBorderPainted(false); button.setContentAreaFilled(false); button.setPreferredSize(new Dimension(130, 40)); button.setCursor(new Cursor(Cursor.HAND_CURSOR)); // 添加鼠标悬停效果 button.addMouseListener(new java.awt.event.MouseAdapter() { @Override public void mouseEntered(java.awt.event.MouseEvent evt) { button.setBackground(backgroundColor.brighter()); button.repaint(); } @Override public void mouseExited(java.awt.event.MouseEvent evt) { button.setBackground(backgroundColor); button.repaint(); } }); return button; } /** * 创建大型难度选择按钮 */ public static JButton createLargeDifficultyButton(String text, Color backgroundColor) { JButton button = new JButton(text) { @Override protected void paintComponent(Graphics g) { Graphics2D g2 = (Graphics2D) g.create(); g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); // 创建渐变效果 GradientPaint gradient = new GradientPaint(0, 0, backgroundColor.brighter(), 0, getHeight(), backgroundColor); g2.setPaint(gradient); g2.fillRoundRect(0, 0, getWidth(), getHeight(), 20, 20); // 添加外阴影效果 g2.setColor(new Color(0, 0, 0, 20)); g2.fillRoundRect(3, 3, getWidth(), getHeight(), 20, 20); // 重新绘制按钮 g2.setPaint(gradient); g2.fillRoundRect(0, 0, getWidth()-3, getHeight()-3, 20, 20); // 添加边框 g2.setColor(backgroundColor.darker()); g2.setStroke(new BasicStroke(2)); g2.drawRoundRect(1, 1, getWidth()-5, getHeight()-5, 18, 18); g2.dispose(); super.paintComponent(g); } }; button.setFont(new Font("微软雅黑", Font.BOLD, 22)); button.setForeground(new Color(40, 40, 40)); button.setFocusPainted(false); button.setBorderPainted(false); button.setContentAreaFilled(false); button.setPreferredSize(new Dimension(320, 70)); button.setCursor(new Cursor(Cursor.HAND_CURSOR)); // 添加鼠标悬停效果 button.addMouseListener(new java.awt.event.MouseAdapter() { @Override public void mouseEntered(java.awt.event.MouseEvent evt) { button.setForeground(new Color(20, 20, 20)); button.repaint(); } @Override public void mouseExited(java.awt.event.MouseEvent evt) { button.setForeground(new Color(40, 40, 40)); button.repaint(); } }); return button; } /** * 发送验证码 */ public static void sendVerificationCode(ActionEvent e, JTextField emailField, Map registeredUsers) { String email = emailField.getText().trim(); if (!isValidEmail(email)) { JOptionPane.showMessageDialog(null, "请输入有效的邮箱地址!", "错误", JOptionPane.ERROR_MESSAGE); return; } // 检查邮箱是否已完成注册(验证码验证成功且设置了密码) RegisteredUser existingUser = registeredUsers.get(email); if (existingUser != null && existingUser.isVerified() && existingUser.getPassword() != null) { JOptionPane.showMessageDialog(null, "该邮箱已注册!", "错误", JOptionPane.ERROR_MESSAGE); return; } // 生成6位验证码 String verificationCode = generateVerificationCode(); // 创建或更新用户对象(仅用于临时存储验证码) RegisteredUser user = new RegisteredUser(email, verificationCode); registeredUsers.put(email, user); // 显示发送中的提示 JOptionPane.showMessageDialog(null, "正在通过QQ邮箱发送验证码到您的邮箱,请稍候...", "发送中", JOptionPane.INFORMATION_MESSAGE); // 在后台线程发送邮件,避免阻塞UI new Thread(() -> { boolean success = QQEmailService.sendVerificationCode(email, verificationCode); // 在EDT线程中显示结果 javax.swing.SwingUtilities.invokeLater(() -> { if (success) { JOptionPane.showMessageDialog(null, "✅ 验证码已通过QQ邮箱发送!\n" + "📧 请查收邮件并输入6位验证码。\n" + "📱 如果没收到,请检查垃圾邮件文件夹。", "发送成功", JOptionPane.INFORMATION_MESSAGE); } else { JOptionPane.showMessageDialog(null, "❌ 验证码发送失败!\n" + "请检查:\n" + "• 接收邮箱地址是否正确\n" + "• QQ邮箱配置是否正确\n" + "• 网络连接是否正常", "发送失败", JOptionPane.ERROR_MESSAGE); // 发送失败时移除用户 registeredUsers.remove(email); } }); }).start(); } /** * 处理用户注册 */ public static boolean handleRegister(JTextField emailField, JTextField verificationCodeField, Map registeredUsers, CardLayout cardLayout, JPanel mainPanel) { String email = emailField.getText().trim(); String code = verificationCodeField.getText().trim(); if (email.isEmpty() || code.isEmpty()) { JOptionPane.showMessageDialog(null, "请填写完整信息!", "错误", JOptionPane.ERROR_MESSAGE); return false; } RegisteredUser user = registeredUsers.get(email); if (user == null) { JOptionPane.showMessageDialog(null, "请先发送验证码!", "错误", JOptionPane.ERROR_MESSAGE); return false; } if (!user.verifyCode(code)) { JOptionPane.showMessageDialog(null, "验证码错误!", "错误", JOptionPane.ERROR_MESSAGE); return false; } user.setVerified(true); JOptionPane.showMessageDialog(null, "注册成功!请设置密码。", "成功", JOptionPane.INFORMATION_MESSAGE); cardLayout.show(mainPanel, "PASSWORD_SETUP"); return true; } /** * 处理密码设置 */ public static boolean handlePasswordSetup(JPasswordField passwordField, JPasswordField confirmPasswordField, Map registeredUsers, CardLayout cardLayout, JPanel mainPanel) { String password = new String(passwordField.getPassword()); String confirmPassword = new String(confirmPasswordField.getPassword()); if (!password.equals(confirmPassword)) { JOptionPane.showMessageDialog(null, "两次输入的密码不一致!", "错误", JOptionPane.ERROR_MESSAGE); return false; } if (!isValidPassword(password)) { JOptionPane.showMessageDialog(null, "密码不符合要求!\n要求:6-10位,必须包含大小写字母和数字", "错误", JOptionPane.ERROR_MESSAGE); return false; } // 找到当前注册的用户 RegisteredUser currentUser = null; for (RegisteredUser user : registeredUsers.values()) { if (user.isVerified() && user.getPassword() == null) { currentUser = user; break; } } if (currentUser != null) { currentUser.setPassword(password); saveUserData(registeredUsers); JOptionPane.showMessageDialog(null, "密码设置成功!", "成功", JOptionPane.INFORMATION_MESSAGE); cardLayout.show(mainPanel, "DIFFICULTY_SELECTION"); return true; } return false; } /** * 处理用户登录 */ public static RegisteredUser handleLogin(String email, String password, Map registeredUsers, CardLayout cardLayout, JPanel mainPanel) { if (email.isEmpty() || password.isEmpty()) { JOptionPane.showMessageDialog(null, "请填写完整信息!", "错误", JOptionPane.ERROR_MESSAGE); return null; } RegisteredUser user = registeredUsers.get(email); if (user == null || !user.isVerified() || !user.verifyPassword(password)) { JOptionPane.showMessageDialog(null, "用户名或密码错误!", "错误", JOptionPane.ERROR_MESSAGE); return null; } JOptionPane.showMessageDialog(null, "登录成功!", "成功", JOptionPane.INFORMATION_MESSAGE); cardLayout.show(mainPanel, "DIFFICULTY_SELECTION"); return user; } /** * 处理密码修改 */ public static boolean handlePasswordChange(String oldPassword, String newPassword, String confirmNewPassword, RegisteredUser currentUser) { if (!currentUser.verifyPassword(oldPassword)) { JOptionPane.showMessageDialog(null, "原密码错误!", "错误", JOptionPane.ERROR_MESSAGE); return false; } if (!newPassword.equals(confirmNewPassword)) { JOptionPane.showMessageDialog(null, "两次输入的新密码不一致!", "错误", JOptionPane.ERROR_MESSAGE); return false; } if (!isValidPassword(newPassword)) { JOptionPane.showMessageDialog(null, "新密码不符合要求!\n要求:6-10位,必须包含大小写字母和数字", "错误", JOptionPane.ERROR_MESSAGE); return false; } currentUser.setPassword(newPassword); JOptionPane.showMessageDialog(null, "密码修改成功!", "成功", JOptionPane.INFORMATION_MESSAGE); return true; } /** * 生成选择题 */ public static List generateQuestions(String difficulty, int count, MathQuestionGenerator generator) { List questions = new ArrayList<>(); Random random = new Random(); int attempts = 0; int maxAttempts = count * 5; // 防止无限循环 while (questions.size() < count && attempts < maxAttempts) { // 生成数学表达式 MathQuestion mathQuestion = generateSingleQuestion(difficulty, generator); String expression = mathQuestion.getExpression(); // 验证表达式语法 if (!ExpressionEvaluator.isValidMathExpression(expression)) { attempts++; continue; } // 计算正确答案 double correctAnswer = evaluateExpression(expression); // 检查答案是否有效 if (Double.isNaN(correctAnswer) || Double.isInfinite(correctAnswer)) { attempts++; continue; } // 生成选项 String[] options = new String[4]; int correctIndex = random.nextInt(4); // 设置正确答案 options[correctIndex] = formatAnswer(correctAnswer); // 生成3个错误答案 String[] wrongAnswers = ExpressionEvaluator.generateWrongAnswers(correctAnswer, 3); int wrongIndex = 0; for (int j = 0; j < 4; j++) { if (j != correctIndex) { options[j] = wrongAnswers[wrongIndex++]; } } MultipleChoiceQuestion question = new MultipleChoiceQuestion( "计算:" + expression + " = ?", options, correctIndex); questions.add(question); attempts = 0; // 重置尝试计数 } return questions; } /** * 生成单个数学题目 */ private static MathQuestion generateSingleQuestion(String difficulty, MathQuestionGenerator generator) { List questions = generator.generateQuestions(difficulty, 1); return questions.get(0); } /** * 计算数学表达式的值 */ private static double evaluateExpression(String expression) { return ExpressionEvaluator.evaluate(expression); } /** * 格式化答案 */ private static String formatAnswer(double answer) { return ExpressionEvaluator.formatAnswer(answer); } /** * 验证邮箱格式 */ public static boolean isValidEmail(String email) { String emailRegex = "^[a-zA-Z0-9_+&*-]+(?:\\.[a-zA-Z0-9_+&*-]+)*@(?:[a-zA-Z0-9-]+\\.)+[a-zA-Z]{2,7}$"; Pattern pattern = Pattern.compile(emailRegex); return pattern.matcher(email).matches(); } /** * 验证密码格式 */ public static boolean isValidPassword(String password) { if (password.length() < 6 || password.length() > 10) { return false; } boolean hasUpper = false, hasLower = false, hasDigit = false; for (char c : password.toCharArray()) { if (Character.isUpperCase(c)) hasUpper = true; else if (Character.isLowerCase(c)) hasLower = true; else if (Character.isDigit(c)) hasDigit = true; } return hasUpper && hasLower && hasDigit; } /** * 生成验证码 */ public static String generateVerificationCode() { Random random = new Random(); StringBuilder code = new StringBuilder(); for (int i = 0; i < 6; i++) { code.append(random.nextInt(10)); } return code.toString(); } /** * 保存用户数据 */ public static void saveUserData(Map users) { try { Path dataFile = Paths.get("user_data.txt"); try (BufferedWriter writer = Files.newBufferedWriter(dataFile)) { for (RegisteredUser user : users.values()) { if (user.isVerified() && user.getPassword() != null) { writer.write(user.getEmail() + ":" + user.getPassword()); writer.newLine(); } } } } catch (IOException e) { System.err.println("保存用户数据失败: " + e.getMessage()); } } /** * 加载用户数据 */ public static void loadUserData(Map users) { try { Path dataFile = Paths.get("user_data.txt"); if (Files.exists(dataFile)) { List lines = Files.readAllLines(dataFile); for (String line : lines) { String[] parts = line.split(":"); if (parts.length == 2) { RegisteredUser user = new RegisteredUser(parts[0], ""); user.setVerified(true); user.setPassword(parts[1]); users.put(parts[0], user); } } } } catch (IOException e) { System.err.println("加载用户数据失败: " + e.getMessage()); } } }