You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
Demo1/src/MathLearningAppMethods.java

465 lines
18 KiB

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

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<String, RegisteredUser> 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<String, RegisteredUser> 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<String, RegisteredUser> 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<String, RegisteredUser> 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<MultipleChoiceQuestion> generateQuestions(String difficulty, int count, MathQuestionGenerator generator) {
List<MultipleChoiceQuestion> 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<MathQuestion> 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<String, RegisteredUser> 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<String, RegisteredUser> users) {
try {
Path dataFile = Paths.get("user_data.txt");
if (Files.exists(dataFile)) {
List<String> 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());
}
}
}