Compare commits
5 Commits
| Author | SHA1 | Date |
|---|---|---|
|
|
45edeab7c5 | 5 months ago |
|
|
a94ed52785 | 5 months ago |
|
|
7d732a38f6 | 5 months ago |
|
|
4827d46231 | 5 months ago |
|
|
76a3573156 | 5 months ago |
Binary file not shown.
Binary file not shown.
Binary file not shown.
@ -0,0 +1,81 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0
|
||||
http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
<groupId>com.mathlearning</groupId>
|
||||
<artifactId>math-learning-app</artifactId>
|
||||
<version>1.0.0</version>
|
||||
<packaging>jar</packaging>
|
||||
|
||||
<name>数学学习软件</name>
|
||||
<description>小初高数学学习系统</description>
|
||||
|
||||
<properties>
|
||||
<maven.compiler.source>11</maven.compiler.source>
|
||||
<maven.compiler.target>11</maven.compiler.target>
|
||||
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||
</properties>
|
||||
|
||||
<dependencies>
|
||||
<!-- Gson for JSON processing -->
|
||||
<dependency>
|
||||
<groupId>com.google.code.gson</groupId>
|
||||
<artifactId>gson</artifactId>
|
||||
<version>2.10.1</version>
|
||||
</dependency>
|
||||
|
||||
<!-- JavaMail for email functionality -->
|
||||
<dependency>
|
||||
<groupId>com.sun.mail</groupId>
|
||||
<artifactId>javax.mail</artifactId>
|
||||
<version>1.6.2</version>
|
||||
</dependency>
|
||||
|
||||
<!-- JAF (JavaBeans Activation Framework) for JavaMail -->
|
||||
<dependency>
|
||||
<groupId>javax.activation</groupId>
|
||||
<artifactId>activation</artifactId>
|
||||
<version>1.1.1</version>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
<build>
|
||||
<sourceDirectory>src</sourceDirectory>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-compiler-plugin</artifactId>
|
||||
<version>3.11.0</version>
|
||||
<configuration>
|
||||
<source>11</source>
|
||||
<target>11</target>
|
||||
</configuration>
|
||||
</plugin>
|
||||
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-jar-plugin</artifactId>
|
||||
<version>3.3.0</version>
|
||||
<configuration>
|
||||
<archive>
|
||||
<manifest>
|
||||
<mainClass>ui.MathLearningApp</mainClass>
|
||||
</manifest>
|
||||
</archive>
|
||||
</configuration>
|
||||
</plugin>
|
||||
|
||||
<plugin>
|
||||
<groupId>org.codehaus.mojo</groupId>
|
||||
<artifactId>exec-maven-plugin</artifactId>
|
||||
<version>3.1.0</version>
|
||||
<configuration>
|
||||
<mainClass>ui.MathLearningApp</mainClass>
|
||||
</configuration>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
</project>
|
||||
@ -0,0 +1,7 @@
|
||||
package model;
|
||||
|
||||
public enum Grade {
|
||||
primary,
|
||||
middle,
|
||||
high
|
||||
}
|
||||
@ -0,0 +1,63 @@
|
||||
package model;
|
||||
|
||||
public class HighMaker extends Student {
|
||||
final static String[] binaryOps = {"+", "-", "*", "/"}; // 操作符
|
||||
final static String[] trigOps = {"sin", "cos", "tan"};
|
||||
int operandCount;
|
||||
String[] questionParts; // 操作数
|
||||
boolean[] specialOpFlags; // 特殊操作符索引序列
|
||||
int parenStart;
|
||||
int parenEnd;
|
||||
|
||||
public HighMaker(String name, String password, String path) {
|
||||
super(name, password, path);
|
||||
}
|
||||
|
||||
// 数据预处理
|
||||
public void getRandom() {
|
||||
this.operandCount = random.nextInt(4) + 2;
|
||||
this.questionParts = new String[this.operandCount];
|
||||
|
||||
// 使用基类方法随机决定特殊操作符的数量和位置
|
||||
this.specialOpFlags = randomMaker(this.operandCount);
|
||||
|
||||
// 生成题目各部分
|
||||
for (int i = 0; i < operandCount; i++) {
|
||||
int operand = random.nextInt(100) + 1;
|
||||
if (specialOpFlags[i]) {
|
||||
String op = trigOps[random.nextInt(trigOps.length)];
|
||||
questionParts[i] = op + "(" + operand + ")";
|
||||
} else {
|
||||
questionParts[i] = String.valueOf(operand);
|
||||
}
|
||||
}
|
||||
|
||||
// 使用基类方法生成有效括号
|
||||
int[] parenPos = bracketMaker(this.operandCount);
|
||||
this.parenStart = parenPos[0];
|
||||
this.parenEnd = parenPos[1];
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String makeOneQuestion() {
|
||||
getRandom();
|
||||
StringBuilder question = new StringBuilder();
|
||||
|
||||
for (int i = 0; i < operandCount; i++) {
|
||||
if (i == parenStart) {
|
||||
question.append("(");
|
||||
}
|
||||
question.append(questionParts[i]);
|
||||
if (i == parenEnd) {
|
||||
question.append(")");
|
||||
}
|
||||
|
||||
if (i < operandCount - 1) {
|
||||
String op = binaryOps[random.nextInt(binaryOps.length)];
|
||||
question.append(" ").append(op).append(" ");
|
||||
}
|
||||
}
|
||||
return question.toString();
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,65 @@
|
||||
package model;
|
||||
|
||||
public class MiddleMaker extends Student {
|
||||
final static String[] binaryOps = {"+", "-", "*", "/"}; // 操作符
|
||||
final static String[] unaryOps = {"^2", "√"};
|
||||
int operandCount;
|
||||
String[] questionParts; // 操作数
|
||||
boolean[] specialOpFlags; // 特殊操作符索引序列
|
||||
int parenStart;
|
||||
int parenEnd;
|
||||
|
||||
public MiddleMaker(String name, String password, String path) {
|
||||
super(name, password, path);
|
||||
}
|
||||
|
||||
// 数据预处理
|
||||
public void getRandom() {
|
||||
this.operandCount = random.nextInt(4) + 2;
|
||||
this.questionParts = new String[this.operandCount];
|
||||
|
||||
// 使用基类方法随机决定特殊操作符的数量和位置
|
||||
this.specialOpFlags = randomMaker(this.operandCount);
|
||||
|
||||
// 生成题目各部分
|
||||
for (int i = 0; i < this.operandCount; i++) {
|
||||
int operand = random.nextInt(100) + 1;
|
||||
if (this.specialOpFlags[i]) {
|
||||
String op = unaryOps[random.nextInt(unaryOps.length)];
|
||||
if (op.equals("√")) {
|
||||
this.questionParts[i] = op + operand;
|
||||
} else {
|
||||
this.questionParts[i] = operand + op;
|
||||
}
|
||||
} else {
|
||||
this.questionParts[i] = String.valueOf(operand);
|
||||
}
|
||||
}
|
||||
|
||||
// 使用基类方法生成有效括号
|
||||
int[] parenPos = bracketMaker(this.operandCount);
|
||||
this.parenStart = parenPos[0];
|
||||
this.parenEnd = parenPos[1];
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String makeOneQuestion() {
|
||||
getRandom();
|
||||
StringBuilder question = new StringBuilder();
|
||||
|
||||
for (int i = 0; i < operandCount; i++) {
|
||||
if (i == parenStart) {
|
||||
question.append("(");
|
||||
}
|
||||
question.append(questionParts[i]);
|
||||
if (i == parenEnd) {
|
||||
question.append(")");
|
||||
}
|
||||
if (i < operandCount - 1) {
|
||||
question.append(" ").append(binaryOps[random.nextInt(binaryOps.length)]).append(" ");
|
||||
}
|
||||
}
|
||||
return question.toString();
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,166 @@
|
||||
package model;
|
||||
|
||||
import java.util.Stack;
|
||||
|
||||
public class PrimaryMaker extends Student {
|
||||
final static char[] operators = {'+', '-', '*', '/'}; // 操作符
|
||||
int operandCount; // 操作数个数
|
||||
int[] operands; // 操作数列表
|
||||
int parenStart; // 左括号索引
|
||||
int parenEnd; // 右括号
|
||||
|
||||
public PrimaryMaker(String name, String password, String path) {
|
||||
super(name, password, path);
|
||||
}
|
||||
|
||||
// 数据预处理
|
||||
public void getRandom() {
|
||||
// 随机决定操作数个数
|
||||
this.operandCount = random.nextInt(4) + 2;
|
||||
this.operands = new int[operandCount];
|
||||
for (int j = 0; j < operandCount; j++) {
|
||||
operands[j] = random.nextInt(100) + 1;
|
||||
}
|
||||
|
||||
// 使用基类方法生成有效括号
|
||||
int[] parenPos = bracketMaker(this.operandCount);
|
||||
this.parenStart = parenPos[0];
|
||||
this.parenEnd = parenPos[1];
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String makeOneQuestion() {
|
||||
String question;
|
||||
while (true) {
|
||||
question = generateSingleQuestion();
|
||||
try {
|
||||
if (isQuestionValid(question)) {
|
||||
break;
|
||||
}
|
||||
} catch (Exception e) {
|
||||
// 如果表达式求值出错,重新生成
|
||||
}
|
||||
}
|
||||
return question;
|
||||
}
|
||||
|
||||
private String generateSingleQuestion() {
|
||||
getRandom();
|
||||
StringBuilder question = new StringBuilder();
|
||||
|
||||
for (int j = 0; j < this.operandCount; j++) {
|
||||
if (j == this.parenStart) {
|
||||
question.append("( ");
|
||||
}
|
||||
question.append(operands[j]);
|
||||
if (j == this.parenEnd) {
|
||||
question.append(" )");
|
||||
}
|
||||
|
||||
if (j < this.operandCount - 1) {
|
||||
char op = operators[random.nextInt(operators.length)];
|
||||
|
||||
// 确保减法时被减数大于减数
|
||||
if (op == '-' && operands[j] < operands[j + 1]) {
|
||||
int temp = operands[j];
|
||||
operands[j] = operands[j + 1];
|
||||
operands[j + 1] = temp;
|
||||
}
|
||||
|
||||
if (op == '/') {
|
||||
this.operands[j + 1] = this.operands[j + 1] == 0 ? 1 : this.operands[j + 1];
|
||||
}
|
||||
question.append(" ").append(op).append(" ");
|
||||
}
|
||||
}
|
||||
return question.toString();
|
||||
}
|
||||
|
||||
private boolean isQuestionValid(String expression) {
|
||||
// 检查中间过程和最终结果是否为负数
|
||||
try {
|
||||
evaluateExpression(expression, true);
|
||||
} catch (ArithmeticException e) {
|
||||
return false; // 捕获到负数异常
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
private double evaluateExpression(String expression, boolean checkNegative) throws ArithmeticException {
|
||||
Stack<Double> numbers = new Stack<>();
|
||||
Stack<Character> ops = new Stack<>();
|
||||
|
||||
for (int i = 0; i < expression.length(); i++) {
|
||||
char c = expression.charAt(i);
|
||||
if (c == ' ') continue;
|
||||
|
||||
if (Character.isDigit(c)) {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
while (i < expression.length() && (Character.isDigit(expression.charAt(i)) || expression.charAt(i) == '.')) {
|
||||
sb.append(expression.charAt(i++));
|
||||
}
|
||||
i--;
|
||||
numbers.push(Double.parseDouble(sb.toString()));
|
||||
} else if (c == '(') {
|
||||
ops.push(c);
|
||||
} else if (c == ')') {
|
||||
while (ops.peek() != '(') {
|
||||
double result = applyOp(ops.pop(), numbers.pop(), numbers.pop());
|
||||
if (checkNegative && result < 0) {
|
||||
throw new ArithmeticException("Negative intermediate result");
|
||||
}
|
||||
numbers.push(result);
|
||||
}
|
||||
ops.pop();
|
||||
} else if (isOperator(c)) {
|
||||
while (!ops.isEmpty() && hasPrecedence(c, ops.peek())) {
|
||||
double result = applyOp(ops.pop(), numbers.pop(), numbers.pop());
|
||||
if (checkNegative && result < 0) {
|
||||
throw new ArithmeticException("Negative intermediate result");
|
||||
}
|
||||
numbers.push(result);
|
||||
}
|
||||
ops.push(c);
|
||||
}
|
||||
}
|
||||
|
||||
while (!ops.isEmpty()) {
|
||||
double result = applyOp(ops.pop(), numbers.pop(), numbers.pop());
|
||||
if (checkNegative && result < 0) {
|
||||
throw new ArithmeticException("Negative intermediate result");
|
||||
}
|
||||
numbers.push(result);
|
||||
}
|
||||
|
||||
double finalResult = numbers.pop();
|
||||
if (checkNegative && finalResult < 0) {
|
||||
throw new ArithmeticException("Negative final result");
|
||||
}
|
||||
return finalResult;
|
||||
}
|
||||
|
||||
private boolean isOperator(char c) {
|
||||
return c == '+' || c == '-' || c == '*' || c == '/';
|
||||
}
|
||||
|
||||
private boolean hasPrecedence(char op1, char op2) {
|
||||
if (op2 == '(' || op2 == ')') {
|
||||
return false;
|
||||
}
|
||||
return (op1 != '*' && op1 != '/') || (op2 != '+' && op2 != '-');
|
||||
}
|
||||
|
||||
private double applyOp(char op, double b, double a) {
|
||||
switch (op) {
|
||||
case '+': return a + b;
|
||||
case '-':
|
||||
if (a < b) throw new ArithmeticException("Negative result in subtraction");
|
||||
return a - b;
|
||||
case '*': return a * b;
|
||||
case '/':
|
||||
if (b == 0) throw new UnsupportedOperationException("Cannot divide by zero");
|
||||
return a / b;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,64 @@
|
||||
package model;
|
||||
|
||||
/**
|
||||
* 题目类
|
||||
* 包含题干、选项和正确答案
|
||||
*/
|
||||
public class Question {
|
||||
private final String questionText;
|
||||
private final String[] options;
|
||||
private final int correctAnswer;
|
||||
private final String expression;
|
||||
|
||||
/**
|
||||
* 构造题目对象
|
||||
*
|
||||
* @param expression 数学表达式
|
||||
* @param questionText 题目文本
|
||||
* @param options 选项数组(4个选项)
|
||||
* @param correctAnswer 正确答案索引(0-3)
|
||||
*/
|
||||
public Question(String expression, String questionText, String[] options,
|
||||
int correctAnswer) {
|
||||
this.expression = expression;
|
||||
this.questionText = questionText;
|
||||
this.options = options;
|
||||
this.correctAnswer = correctAnswer;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取题目文本
|
||||
*
|
||||
* @return 题目文本
|
||||
*/
|
||||
public String getQuestionText() {
|
||||
return questionText;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取选项数组
|
||||
*
|
||||
* @return 选项数组
|
||||
*/
|
||||
public String[] getOptions() {
|
||||
return options;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取正确答案索引
|
||||
*
|
||||
* @return 正确答案索引
|
||||
*/
|
||||
public int getCorrectAnswer() {
|
||||
return correctAnswer;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取数学表达式
|
||||
*
|
||||
* @return 数学表达式
|
||||
*/
|
||||
public String getExpression() {
|
||||
return expression;
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,61 @@
|
||||
package model;
|
||||
|
||||
import java.util.Random;
|
||||
|
||||
public abstract class Student {
|
||||
protected String name;
|
||||
protected String password;
|
||||
protected String path;
|
||||
protected Random random;
|
||||
|
||||
public Student(String name, String password, String path) {
|
||||
this.name = name;
|
||||
this.password = password;
|
||||
this.path = path;
|
||||
this.random = new Random();
|
||||
}
|
||||
|
||||
/**
|
||||
* 生成有效的括号位置
|
||||
* 确保括号不会包围整个表达式
|
||||
*
|
||||
* @param operands 操作数数量
|
||||
* @return 包含起始和结束位置的数组 [parenStart, parenEnd]
|
||||
*/
|
||||
protected int[] bracketMaker(int operands) {
|
||||
boolean useParen = operands > 2 && random.nextBoolean();
|
||||
int parenStart = 0;
|
||||
int parenEnd = operands - 1;
|
||||
|
||||
while (parenStart == 0 && parenEnd == operands - 1) {
|
||||
parenStart = useParen ? random.nextInt(operands - 1) : -2;
|
||||
parenEnd = useParen ? random.nextInt(operands - 1 - parenStart) + parenStart + 1 : -2;
|
||||
}
|
||||
|
||||
return new int[]{parenStart, parenEnd};
|
||||
}
|
||||
|
||||
/**
|
||||
* 随机选择特殊操作符的位置
|
||||
*
|
||||
* @param operands 操作数数量
|
||||
* @return 标记特殊操作符位置的布尔数组
|
||||
*/
|
||||
protected boolean[] randomMaker(int operands) {
|
||||
int specialNumber = Math.min(operands, random.nextInt(operands) + 1);
|
||||
boolean[] specialOpFlags = new boolean[operands];
|
||||
|
||||
for (int i = 0; i < specialNumber; i++) {
|
||||
int pos;
|
||||
do {
|
||||
pos = random.nextInt(operands);
|
||||
} while (specialOpFlags[pos]);
|
||||
specialOpFlags[pos] = true;
|
||||
}
|
||||
|
||||
return specialOpFlags;
|
||||
}
|
||||
|
||||
protected abstract String makeOneQuestion();
|
||||
|
||||
}
|
||||
@ -0,0 +1,159 @@
|
||||
package ui;
|
||||
|
||||
import model.UserManager;
|
||||
import javax.swing.BorderFactory;
|
||||
import javax.swing.JButton;
|
||||
import javax.swing.JDialog;
|
||||
import javax.swing.JLabel;
|
||||
import javax.swing.JOptionPane;
|
||||
import javax.swing.JPanel;
|
||||
import javax.swing.JPasswordField;
|
||||
import java.awt.Dimension;
|
||||
import java.awt.Font;
|
||||
import java.awt.Frame;
|
||||
import java.awt.GridBagConstraints;
|
||||
import java.awt.GridBagLayout;
|
||||
import java.awt.Insets;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
/**
|
||||
* 修改密码对话框
|
||||
* 用户在登录状态下可以修改密码
|
||||
*/
|
||||
public class ChangePasswordDialog extends JDialog {
|
||||
private static final long serialVersionUID = 1L;
|
||||
private static final Pattern PASSWORD_PATTERN =
|
||||
Pattern.compile("^(?=.*[a-z])(?=.*[A-Z])(?=.*\\d)[a-zA-Z0-9]{6,10}$");
|
||||
|
||||
private final JPasswordField oldPasswordField;
|
||||
private final JPasswordField newPassword1Field;
|
||||
private final JPasswordField newPassword2Field;
|
||||
private final JButton confirmButton;
|
||||
private final UserManager userManager;
|
||||
private final String email;
|
||||
|
||||
/**
|
||||
* 构造修改密码对话框
|
||||
*
|
||||
* @param parent 父窗口
|
||||
* @param email 用户邮箱
|
||||
*/
|
||||
public ChangePasswordDialog(Frame parent, String email) {
|
||||
super(parent, "修改密码", true);
|
||||
this.email = email;
|
||||
this.userManager = new UserManager();
|
||||
|
||||
setSize(600, 360);
|
||||
setLocationRelativeTo(parent);
|
||||
setResizable(true);
|
||||
|
||||
JPanel panel = new JPanel(new GridBagLayout());
|
||||
panel.setBorder(BorderFactory.createEmptyBorder(20, 20, 20, 20));
|
||||
GridBagConstraints gbc = new GridBagConstraints();
|
||||
gbc.insets = new Insets(5, 5, 5, 5);
|
||||
gbc.fill = GridBagConstraints.HORIZONTAL;
|
||||
|
||||
JLabel infoLabel = new JLabel("<html>新密码要求:<br>" +
|
||||
"1. 长度 6-10位<br>" +
|
||||
"2. 必须包含大写字母<br>" +
|
||||
"3. 必须包含小写字母<br>" +
|
||||
"4. 必须包含数字<br>" +
|
||||
"5. 不能包含特殊字符</html>");
|
||||
infoLabel.setFont(new Font("微软雅黑", Font.PLAIN, 11));
|
||||
gbc.gridx = 0;
|
||||
gbc.gridy = 0;
|
||||
gbc.gridwidth = 2;
|
||||
panel.add(infoLabel, gbc);
|
||||
|
||||
gbc.gridwidth = 1;
|
||||
gbc.gridy = 1;
|
||||
panel.add(new JLabel("原密码:"), gbc);
|
||||
|
||||
oldPasswordField = new JPasswordField(20);
|
||||
gbc.gridx = 1;
|
||||
gbc.weightx = 1.0;
|
||||
panel.add(oldPasswordField, gbc);
|
||||
gbc.weightx = 0.0;
|
||||
|
||||
gbc.gridx = 0;
|
||||
gbc.gridy = 2;
|
||||
panel.add(new JLabel("新密码:"), gbc);
|
||||
|
||||
newPassword1Field = new JPasswordField(20);
|
||||
gbc.gridx = 1;
|
||||
gbc.weightx = 1.0;
|
||||
panel.add(newPassword1Field, gbc);
|
||||
gbc.weightx = 0.0;
|
||||
|
||||
gbc.gridx = 0;
|
||||
gbc.gridy = 3;
|
||||
panel.add(new JLabel("确认新密码:"), gbc);
|
||||
|
||||
newPassword2Field = new JPasswordField(20);
|
||||
gbc.gridx = 1;
|
||||
gbc.weightx = 1.0;
|
||||
panel.add(newPassword2Field, gbc);
|
||||
gbc.weightx = 0.0;
|
||||
|
||||
confirmButton = new JButton("确认修改");
|
||||
confirmButton.setPreferredSize(new Dimension(120, 30));
|
||||
gbc.gridx = 0;
|
||||
gbc.gridy = 4;
|
||||
gbc.gridwidth = 2;
|
||||
gbc.anchor = GridBagConstraints.CENTER;
|
||||
panel.add(confirmButton, gbc);
|
||||
|
||||
add(panel);
|
||||
|
||||
confirmButton.addActionListener(e -> handleConfirm());
|
||||
getRootPane().setDefaultButton(confirmButton);
|
||||
}
|
||||
|
||||
/**
|
||||
* 处理确认修改
|
||||
*/
|
||||
private void handleConfirm() {
|
||||
String oldPassword = new String(oldPasswordField.getPassword());
|
||||
String newPassword1 = new String(newPassword1Field.getPassword());
|
||||
String newPassword2 = new String(newPassword2Field.getPassword());
|
||||
|
||||
if (oldPassword.isEmpty() || newPassword1.isEmpty() ||
|
||||
newPassword2.isEmpty()) {
|
||||
showError("所有字段都不能为空");
|
||||
return;
|
||||
}
|
||||
|
||||
if (!newPassword1.equals(newPassword2)) {
|
||||
showError("两次输入的新密码不一致");
|
||||
return;
|
||||
}
|
||||
|
||||
if (!PASSWORD_PATTERN.matcher(newPassword1).matches()) {
|
||||
showError("新密码不符合要求:\n" +
|
||||
"长度6-10位, 必须包含大小写字母和数字, 且不能包含特殊字符");
|
||||
return;
|
||||
}
|
||||
|
||||
if (userManager.changePassword(email, oldPassword, newPassword1)) {
|
||||
JOptionPane.showMessageDialog(this,
|
||||
"密码修改成功!",
|
||||
"成功",
|
||||
JOptionPane.INFORMATION_MESSAGE);
|
||||
dispose();
|
||||
} else {
|
||||
showError("原密码错误");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 显示错误信息
|
||||
*
|
||||
* @param message 错误消息
|
||||
*/
|
||||
private void showError(String message) {
|
||||
JOptionPane.showMessageDialog(this,
|
||||
message,
|
||||
"错误",
|
||||
JOptionPane.ERROR_MESSAGE);
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,24 @@
|
||||
package ui;
|
||||
|
||||
import javax.swing.SwingUtilities;
|
||||
|
||||
/**
|
||||
* 数学学习软件主入口
|
||||
*
|
||||
* @author 结对项目
|
||||
* @version 1.0
|
||||
*/
|
||||
public class MathLearningApp {
|
||||
|
||||
/**
|
||||
* 程序主入口
|
||||
*
|
||||
* @param args 命令行参数
|
||||
*/
|
||||
public static void main(String[] args) {
|
||||
SwingUtilities.invokeLater(() -> {
|
||||
LoginFrame loginFrame = new LoginFrame();
|
||||
loginFrame.setVisible(true);
|
||||
});
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,215 @@
|
||||
package ui;
|
||||
|
||||
import model.Grade;
|
||||
import model.UserManager;
|
||||
import javax.swing.BorderFactory;
|
||||
import javax.swing.JButton;
|
||||
import javax.swing.JComboBox;
|
||||
import javax.swing.JDialog;
|
||||
import javax.swing.JLabel;
|
||||
import javax.swing.JOptionPane;
|
||||
import javax.swing.JPanel;
|
||||
import javax.swing.JPasswordField;
|
||||
import javax.swing.JTextField;
|
||||
import java.awt.Dimension;
|
||||
import java.awt.Frame;
|
||||
import java.awt.Font;
|
||||
import java.awt.GridBagConstraints;
|
||||
import java.awt.GridBagLayout;
|
||||
import java.awt.Insets;
|
||||
import java.io.Serial;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
/**
|
||||
* 密码设置对话框
|
||||
* 用于新用户注册时设置密码和选择年级
|
||||
*/
|
||||
public class PasswordSetupDialog extends JDialog {
|
||||
@Serial
|
||||
private static final long serialVersionUID = 1L;
|
||||
private static final Pattern PASSWORD_PATTERN =
|
||||
Pattern.compile("^(?=.*[a-z])(?=.*[A-Z])(?=.*\\d)[a-zA-Z0-9]{6,10}$");
|
||||
|
||||
private final JTextField usernameField;
|
||||
private final JPasswordField password1Field;
|
||||
private final JPasswordField password2Field;
|
||||
private final JComboBox<String> gradeComboBox;
|
||||
private final JButton confirmButton;
|
||||
private final UserManager userManager;
|
||||
private final String email;
|
||||
private boolean registrationComplete;
|
||||
|
||||
/**
|
||||
* 构造密码设置对话框
|
||||
*
|
||||
* @param parent 父窗口
|
||||
* @param userManager 用户管理器
|
||||
* @param email 用户邮箱
|
||||
*/
|
||||
public PasswordSetupDialog(Frame parent, UserManager userManager, String email) {
|
||||
super(parent, "设置密码和用户名", true);
|
||||
this.userManager = userManager;
|
||||
this.email = email;
|
||||
this.registrationComplete = false;
|
||||
|
||||
setSize(600, 420);
|
||||
setLocationRelativeTo(parent);
|
||||
setResizable(true);
|
||||
|
||||
JPanel panel = new JPanel(new GridBagLayout());
|
||||
panel.setBorder(BorderFactory.createEmptyBorder(20, 20, 20, 20));
|
||||
GridBagConstraints gbc = new GridBagConstraints();
|
||||
gbc.insets = new Insets(5, 5, 5, 5);
|
||||
gbc.fill = GridBagConstraints.HORIZONTAL;
|
||||
|
||||
JLabel infoLabel = new JLabel("<html>密码要求:<br>" +
|
||||
"1. 长度 6-10位<br>" +
|
||||
"2. 必须包含大写字母<br>" +
|
||||
"3. 必须包含小写字母<br>" +
|
||||
"4. 必须包含数字<br>" +
|
||||
"5. 不能包含其他特殊字符</html>");
|
||||
infoLabel.setFont(new Font("微软雅黑", Font.PLAIN, 11));
|
||||
gbc.gridx = 0;
|
||||
gbc.gridy = 0;
|
||||
gbc.gridwidth = 2;
|
||||
panel.add(infoLabel, gbc);
|
||||
|
||||
gbc.gridwidth = 1;
|
||||
gbc.gridy = 1;
|
||||
panel.add(new JLabel("输入密码:"), gbc);
|
||||
|
||||
password1Field = new JPasswordField(20);
|
||||
gbc.gridx = 1;
|
||||
gbc.weightx = 1.0;
|
||||
panel.add(password1Field, gbc);
|
||||
gbc.weightx = 0.0;
|
||||
|
||||
gbc.gridx = 0;
|
||||
gbc.gridy = 2;
|
||||
panel.add(new JLabel("确认密码:"), gbc);
|
||||
|
||||
password2Field = new JPasswordField(20);
|
||||
gbc.gridx = 1;
|
||||
gbc.weightx = 1.0;
|
||||
panel.add(password2Field, gbc);
|
||||
gbc.weightx = 0.0;
|
||||
|
||||
gbc.gridx = 0;
|
||||
gbc.gridy = 3;
|
||||
panel.add(new JLabel("设置用户名:"), gbc);
|
||||
|
||||
usernameField = new JTextField(20);
|
||||
gbc.gridx = 1;
|
||||
gbc.weightx = 1.0;
|
||||
panel.add(usernameField, gbc);
|
||||
gbc.weightx = 0.0;
|
||||
|
||||
gbc.gridx = 0;
|
||||
gbc.gridy = 4;
|
||||
panel.add(new JLabel("选择年级:"), gbc);
|
||||
|
||||
String[] grades = {"小学", "初中", "高中"};
|
||||
gradeComboBox = new JComboBox<>(grades);
|
||||
gbc.gridx = 1;
|
||||
gbc.weightx = 1.0;
|
||||
panel.add(gradeComboBox, gbc);
|
||||
gbc.weightx = 0.0;
|
||||
|
||||
confirmButton = new JButton("确认注册");
|
||||
confirmButton.setPreferredSize(new Dimension(120, 30));
|
||||
gbc.gridx = 0;
|
||||
gbc.gridy = 5;
|
||||
gbc.gridwidth = 2;
|
||||
gbc.anchor = GridBagConstraints.CENTER;
|
||||
panel.add(confirmButton, gbc);
|
||||
|
||||
add(panel);
|
||||
|
||||
confirmButton.addActionListener(e -> handleConfirm());
|
||||
getRootPane().setDefaultButton(confirmButton);
|
||||
}
|
||||
|
||||
/**
|
||||
* 处理确认注册
|
||||
*/
|
||||
private void handleConfirm() {
|
||||
String password1 = new String(password1Field.getPassword());
|
||||
String password2 = new String(password2Field.getPassword());
|
||||
String username = usernameField.getText().trim();
|
||||
|
||||
if (username.isEmpty() || password1.isEmpty() || password2.isEmpty()) {
|
||||
showError("用户名和密码不能为空");
|
||||
return;
|
||||
}
|
||||
|
||||
if (userManager.usernameExists(username)) {
|
||||
showError("该用户名已被使用,请更换一个");
|
||||
return;
|
||||
}
|
||||
|
||||
if (!password1.equals(password2)) {
|
||||
showError("两次输入的密码不一致");
|
||||
return;
|
||||
}
|
||||
|
||||
if (!PASSWORD_PATTERN.matcher(password1).matches()) {
|
||||
showError("密码不符合要求:\n" +
|
||||
"长度6-10位, 必须包含大小写字母和数字, 且不能包含特殊字符");
|
||||
return;
|
||||
}
|
||||
|
||||
Grade gradeType = getSelectedGradeType();
|
||||
boolean success = userManager.register(email, password1, gradeType, username);
|
||||
|
||||
if (success) {
|
||||
JOptionPane.showMessageDialog(this,
|
||||
"注册成功!请返回登录。",
|
||||
"成功",
|
||||
JOptionPane.INFORMATION_MESSAGE);
|
||||
registrationComplete = true;
|
||||
dispose();
|
||||
} else {
|
||||
showError("注册失败,该邮箱可能已被注册");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取选择的年级类型
|
||||
*
|
||||
* @return 年级类型
|
||||
*/
|
||||
private Grade getSelectedGradeType() {
|
||||
String selected = (String) gradeComboBox.getSelectedItem();
|
||||
switch (selected) {
|
||||
case "小学":
|
||||
return Grade.primary;
|
||||
case "初中":
|
||||
return Grade.middle;
|
||||
case "高中":
|
||||
return Grade.high;
|
||||
default:
|
||||
return Grade.primary;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 显示错误信息
|
||||
*
|
||||
* @param message 错误消息
|
||||
*/
|
||||
private void showError(String message) {
|
||||
JOptionPane.showMessageDialog(this,
|
||||
message,
|
||||
"错误",
|
||||
JOptionPane.ERROR_MESSAGE);
|
||||
}
|
||||
|
||||
/**
|
||||
* 检查注册是否完成
|
||||
*
|
||||
* @return 注册是否完成
|
||||
*/
|
||||
public boolean isRegistrationComplete() {
|
||||
return registrationComplete;
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,210 @@
|
||||
package ui;
|
||||
|
||||
import model.Grade;
|
||||
import model.Question;
|
||||
import model.QuestionMaker;
|
||||
|
||||
import javax.swing.BorderFactory;
|
||||
import javax.swing.ButtonGroup;
|
||||
import javax.swing.JButton;
|
||||
import javax.swing.JFrame;
|
||||
import javax.swing.JLabel;
|
||||
import javax.swing.JOptionPane;
|
||||
import javax.swing.JPanel;
|
||||
import javax.swing.JRadioButton;
|
||||
import java.awt.BorderLayout;
|
||||
import java.awt.Dimension;
|
||||
import java.awt.FlowLayout;
|
||||
import java.awt.Font;
|
||||
import java.awt.GridBagConstraints;
|
||||
import java.awt.GridBagLayout;
|
||||
import java.awt.Insets;
|
||||
import java.io.Serial;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 答题界面
|
||||
* 显示题目和选项,接收用户答案
|
||||
*/
|
||||
public class QuizFrame extends JFrame {
|
||||
@Serial
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
private final String email;
|
||||
private final Grade gradeType;
|
||||
private final List<Question> questions;
|
||||
private int currentIndex;
|
||||
private int correctCount;
|
||||
|
||||
private JLabel questionLabel;
|
||||
private JLabel progressLabel;
|
||||
private JRadioButton[] optionButtons;
|
||||
private JButton submitButton;
|
||||
private ButtonGroup optionGroup;
|
||||
|
||||
/**
|
||||
* 构造答题界面
|
||||
*
|
||||
* @param email 用户邮箱
|
||||
* @param gradeType 年级类型
|
||||
* @param questionCount 题目数量
|
||||
*/
|
||||
public QuizFrame(String email, Grade gradeType, int questionCount) {
|
||||
this.email = email;
|
||||
this.gradeType = gradeType;
|
||||
this.currentIndex = 0;
|
||||
this.correctCount = 0;
|
||||
|
||||
QuestionMaker generator = new QuestionMaker();
|
||||
this.questions = generator.makeQuestions(gradeType, questionCount, email);
|
||||
|
||||
if (questions.isEmpty()) {
|
||||
JOptionPane.showMessageDialog(null,
|
||||
"生成题目失败,返回主界面",
|
||||
"错误",
|
||||
JOptionPane.ERROR_MESSAGE);
|
||||
returnToGradeSelection();
|
||||
return;
|
||||
}
|
||||
|
||||
setTitle("数学学习软件 - 答题");
|
||||
setSize(900, 600);
|
||||
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
|
||||
setLocationRelativeTo(null);
|
||||
setResizable(true);
|
||||
|
||||
JPanel mainPanel = new JPanel(new BorderLayout(10, 10));
|
||||
mainPanel.setBorder(BorderFactory.createEmptyBorder(20, 20, 20, 20));
|
||||
|
||||
progressLabel = new JLabel("", JLabel.CENTER);
|
||||
progressLabel.setFont(new Font("微软雅黑", Font.BOLD, 14));
|
||||
mainPanel.add(progressLabel, BorderLayout.NORTH);
|
||||
|
||||
JPanel centerPanel = new JPanel(new GridBagLayout());
|
||||
GridBagConstraints gbc = new GridBagConstraints();
|
||||
gbc.insets = new Insets(10, 10, 10, 10);
|
||||
gbc.fill = GridBagConstraints.HORIZONTAL;
|
||||
|
||||
// 新增:答案格式提示
|
||||
JLabel answerFormatLabel = new JLabel("注意:所有计算结果的答案均保留两位小数。", JLabel.CENTER);
|
||||
answerFormatLabel.setFont(new Font("微软雅黑", Font.ITALIC, 12));
|
||||
gbc.gridx = 0;
|
||||
gbc.gridy = 0;
|
||||
gbc.gridwidth = 2;
|
||||
centerPanel.add(answerFormatLabel, gbc);
|
||||
|
||||
gbc.gridx = 0;
|
||||
gbc.gridy = 1;
|
||||
gbc.gridwidth = 2;
|
||||
|
||||
questionLabel = new JLabel();
|
||||
questionLabel.setFont(new Font("Cambria Math", Font.PLAIN, 18));
|
||||
questionLabel.setBorder(BorderFactory.createEmptyBorder(10, 10, 20, 10));
|
||||
centerPanel.add(questionLabel, gbc);
|
||||
|
||||
optionGroup = new ButtonGroup();
|
||||
optionButtons = new JRadioButton[4];
|
||||
|
||||
for (int i = 0; i < 4; i++) {
|
||||
optionButtons[i] = new JRadioButton();
|
||||
optionButtons[i].setFont(new Font("Cambria Math", Font.PLAIN, 14));
|
||||
optionGroup.add(optionButtons[i]);
|
||||
gbc.gridy = i + 2;
|
||||
gbc.gridwidth = 2;
|
||||
centerPanel.add(optionButtons[i], gbc);
|
||||
gbc.gridwidth = 1;
|
||||
}
|
||||
|
||||
mainPanel.add(centerPanel, BorderLayout.CENTER);
|
||||
|
||||
JPanel bottomPanel = new JPanel(new FlowLayout(FlowLayout.CENTER));
|
||||
submitButton = new JButton("提交答案");
|
||||
submitButton.setPreferredSize(new Dimension(150, 35));
|
||||
submitButton.setFont(new Font("微软雅黑", Font.BOLD, 14));
|
||||
bottomPanel.add(submitButton);
|
||||
|
||||
mainPanel.add(bottomPanel, BorderLayout.SOUTH);
|
||||
|
||||
add(mainPanel);
|
||||
|
||||
submitButton.addActionListener(e -> handleSubmit());
|
||||
|
||||
displayQuestion();
|
||||
}
|
||||
|
||||
/**
|
||||
* 显示当前题目
|
||||
*/
|
||||
private void displayQuestion() {
|
||||
if (currentIndex >= questions.size()) {
|
||||
showResult();
|
||||
return;
|
||||
}
|
||||
|
||||
Question question = questions.get(currentIndex);
|
||||
progressLabel.setText(String.format("第 %d/%d 题",
|
||||
currentIndex + 1, questions.size()));
|
||||
questionLabel.setText("<html><body style='width: 500px'>" +
|
||||
question.getQuestionText() + "</body></html>");
|
||||
|
||||
optionGroup.clearSelection();
|
||||
|
||||
String[] options = question.getOptions();
|
||||
for (int i = 0; i < 4; i++) {
|
||||
optionButtons[i].setText(options[i]);
|
||||
}
|
||||
|
||||
submitButton.setEnabled(true);
|
||||
}
|
||||
|
||||
/**
|
||||
* 处理答案提交
|
||||
*/
|
||||
private void handleSubmit() {
|
||||
int selectedIndex = -1;
|
||||
for (int i = 0; i < 4; i++) {
|
||||
if (optionButtons[i].isSelected()) {
|
||||
selectedIndex = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (selectedIndex == -1) {
|
||||
JOptionPane.showMessageDialog(this,
|
||||
"请选择一个答案",
|
||||
"提示",
|
||||
JOptionPane.WARNING_MESSAGE);
|
||||
return;
|
||||
}
|
||||
|
||||
Question question = questions.get(currentIndex);
|
||||
if (selectedIndex == question.getCorrectAnswer()) {
|
||||
correctCount++;
|
||||
}
|
||||
|
||||
currentIndex++;
|
||||
displayQuestion();
|
||||
}
|
||||
|
||||
/**
|
||||
* 显示答题结果
|
||||
*/
|
||||
private void showResult() {
|
||||
double percentage = (double) correctCount / questions.size() * 100;
|
||||
int score = (int) percentage;
|
||||
|
||||
ResultFrame resultFrame = new ResultFrame(
|
||||
email, gradeType, score, correctCount, questions.size());
|
||||
resultFrame.setVisible(true);
|
||||
this.dispose();
|
||||
}
|
||||
|
||||
/**
|
||||
* 返回年级选择界面
|
||||
*/
|
||||
private void returnToGradeSelection() {
|
||||
GradeSelectionFrame frame = new GradeSelectionFrame(email, gradeType);
|
||||
frame.setVisible(true);
|
||||
this.dispose();
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,127 @@
|
||||
package ui;
|
||||
|
||||
import model.Grade;
|
||||
import javax.swing.BorderFactory;
|
||||
import javax.swing.JButton;
|
||||
import javax.swing.JFrame;
|
||||
import javax.swing.JLabel;
|
||||
import javax.swing.JPanel;
|
||||
import java.awt.BorderLayout;
|
||||
import java.awt.Color;
|
||||
import java.awt.Dimension;
|
||||
import java.awt.FlowLayout;
|
||||
import java.awt.Font;
|
||||
import java.awt.GridBagConstraints;
|
||||
import java.awt.GridBagLayout;
|
||||
import java.awt.Insets;
|
||||
|
||||
/**
|
||||
* 答题结果展示界面
|
||||
* 显示得分和统计信息,提供继续答题或退出选项
|
||||
*/
|
||||
public class ResultFrame extends JFrame {
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
private final String email;
|
||||
private final Grade gradeType;
|
||||
|
||||
/**
|
||||
* 构造结果展示界面
|
||||
*
|
||||
* @param email 用户邮箱
|
||||
* @param gradeType 年级类型
|
||||
* @param score 得分
|
||||
* @param correctCount 答对题数
|
||||
* @param totalCount 总题数
|
||||
*/
|
||||
public ResultFrame(String email, Grade gradeType, int score,
|
||||
int correctCount, int totalCount) {
|
||||
this.email = email;
|
||||
this.gradeType = gradeType;
|
||||
|
||||
setTitle("数学学习软件 - 答题结果");
|
||||
setSize(600, 420);
|
||||
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
|
||||
setLocationRelativeTo(null);
|
||||
setResizable(true);
|
||||
|
||||
JPanel mainPanel = new JPanel(new BorderLayout(10, 10));
|
||||
mainPanel.setBorder(BorderFactory.createEmptyBorder(30, 30, 30, 30));
|
||||
|
||||
JPanel centerPanel = new JPanel(new GridBagLayout());
|
||||
GridBagConstraints gbc = new GridBagConstraints();
|
||||
gbc.insets = new Insets(10, 10, 10, 10);
|
||||
gbc.gridx = 0;
|
||||
gbc.gridy = 0;
|
||||
|
||||
JLabel titleLabel = new JLabel("答题完成!", JLabel.CENTER);
|
||||
titleLabel.setFont(new Font("微软雅黑", Font.BOLD, 24));
|
||||
centerPanel.add(titleLabel, gbc);
|
||||
|
||||
gbc.gridy = 1;
|
||||
JLabel scoreLabel = new JLabel("得分: " + score, JLabel.CENTER);
|
||||
scoreLabel.setFont(new Font("微软雅黑", Font.BOLD, 36));
|
||||
scoreLabel.setForeground(getScoreColor(score));
|
||||
centerPanel.add(scoreLabel, gbc);
|
||||
|
||||
gbc.gridy = 2;
|
||||
JLabel detailLabel = new JLabel(
|
||||
String.format("答对 %d 题 / 共 %d 题", correctCount, totalCount),
|
||||
JLabel.CENTER);
|
||||
detailLabel.setFont(new Font("微软雅黑", Font.PLAIN, 14));
|
||||
centerPanel.add(detailLabel, gbc);
|
||||
|
||||
mainPanel.add(centerPanel, BorderLayout.CENTER);
|
||||
|
||||
JPanel buttonPanel = new JPanel(new FlowLayout(FlowLayout.CENTER, 15, 0));
|
||||
JButton continueButton = new JButton("继续做题");
|
||||
JButton exitButton = new JButton("退出");
|
||||
|
||||
continueButton.setPreferredSize(new Dimension(120, 35));
|
||||
exitButton.setPreferredSize(new Dimension(120, 35));
|
||||
|
||||
buttonPanel.add(continueButton);
|
||||
buttonPanel.add(exitButton);
|
||||
|
||||
mainPanel.add(buttonPanel, BorderLayout.SOUTH);
|
||||
|
||||
add(mainPanel);
|
||||
|
||||
continueButton.addActionListener(e -> continueQuiz());
|
||||
exitButton.addActionListener(e -> exitToSelection());
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据分数返回对应颜色
|
||||
*
|
||||
* @param score 分数
|
||||
* @return 颜色对象
|
||||
*/
|
||||
private Color getScoreColor(int score) {
|
||||
if (score >= 90) {
|
||||
return new Color(0, 150, 0);
|
||||
} else if (score >= 60) {
|
||||
return new Color(255, 140, 0);
|
||||
} else {
|
||||
return new Color(200, 0, 0);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 继续做题
|
||||
*/
|
||||
private void continueQuiz() {
|
||||
GradeSelectionFrame frame = new GradeSelectionFrame(email, gradeType);
|
||||
frame.setVisible(true);
|
||||
this.dispose();
|
||||
}
|
||||
|
||||
/**
|
||||
* 退出到选择界面
|
||||
*/
|
||||
private void exitToSelection() {
|
||||
GradeSelectionFrame frame = new GradeSelectionFrame(email, gradeType);
|
||||
frame.setVisible(true);
|
||||
this.dispose();
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,86 @@
|
||||
package ui;
|
||||
|
||||
import javax.swing.*;
|
||||
import java.awt.*;
|
||||
|
||||
/**
|
||||
* 用户设置对话框
|
||||
* 显示用户信息并提供修改密码的入口
|
||||
*/
|
||||
public class UserSettingsDialog extends JDialog {
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
private final String email;
|
||||
private final String username;
|
||||
private final Frame parentFrame;
|
||||
|
||||
/**
|
||||
* 构造用户设置对话框
|
||||
*
|
||||
* @param parent 父窗口
|
||||
* @param email 用户邮箱
|
||||
* @param username 用户名
|
||||
*/
|
||||
public UserSettingsDialog(Frame parent, String email, String username) {
|
||||
super(parent, "用户设置", true);
|
||||
this.parentFrame = parent;
|
||||
this.email = email;
|
||||
this.username = username;
|
||||
|
||||
setSize(400, 250);
|
||||
setLocationRelativeTo(parent);
|
||||
setResizable(false);
|
||||
|
||||
JPanel panel = new JPanel(new GridBagLayout());
|
||||
panel.setBorder(BorderFactory.createEmptyBorder(20, 20, 20, 20));
|
||||
GridBagConstraints gbc = new GridBagConstraints();
|
||||
gbc.insets = new Insets(10, 5, 10, 5);
|
||||
gbc.anchor = GridBagConstraints.WEST;
|
||||
|
||||
// 显示用户名
|
||||
gbc.gridx = 0;
|
||||
gbc.gridy = 0;
|
||||
panel.add(new JLabel("用户名:"), gbc);
|
||||
|
||||
gbc.gridx = 1;
|
||||
JLabel usernameLabel = new JLabel(username);
|
||||
usernameLabel.setFont(new Font("微软雅黑", Font.BOLD, 14));
|
||||
panel.add(usernameLabel, gbc);
|
||||
|
||||
// 显示邮箱
|
||||
gbc.gridx = 0;
|
||||
gbc.gridy = 1;
|
||||
panel.add(new JLabel("邮箱:"), gbc);
|
||||
|
||||
gbc.gridx = 1;
|
||||
JLabel emailLabel = new JLabel(email);
|
||||
emailLabel.setFont(new Font("微软雅黑", Font.PLAIN, 14));
|
||||
panel.add(emailLabel, gbc);
|
||||
|
||||
// 修改密码按钮
|
||||
JButton changePasswordButton = new JButton("修改密码");
|
||||
changePasswordButton.setPreferredSize(new Dimension(120, 30));
|
||||
gbc.gridx = 0;
|
||||
gbc.gridy = 2;
|
||||
gbc.gridwidth = 2;
|
||||
gbc.anchor = GridBagConstraints.CENTER;
|
||||
gbc.insets = new Insets(20, 5, 10, 5);
|
||||
panel.add(changePasswordButton, gbc);
|
||||
|
||||
add(panel);
|
||||
|
||||
// 按钮点击事件
|
||||
changePasswordButton.addActionListener(e -> openChangePasswordDialog());
|
||||
}
|
||||
|
||||
/**
|
||||
* 打开修改密码对话框
|
||||
*/
|
||||
private void openChangePasswordDialog() {
|
||||
// 关闭当前对话框
|
||||
this.dispose();
|
||||
// 打开修改密码对话框
|
||||
ChangePasswordDialog dialog = new ChangePasswordDialog(parentFrame, email);
|
||||
dialog.setVisible(true);
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,24 @@
|
||||
ui\ChangePasswordDialog.class
|
||||
ui\UserSettingsDialog.class
|
||||
ui\QuizFrame.class
|
||||
ui\RegisterDialog$1.class
|
||||
model\QuestionMaker.class
|
||||
model\UserManager.class
|
||||
ui\GradeSelectionFrame$1.class
|
||||
ui\ResultFrame.class
|
||||
model\UserManager$1.class
|
||||
model\Grade.class
|
||||
ui\GradeSelectionFrame.class
|
||||
model\PrimaryMaker.class
|
||||
model\UserManager$UserInfo.class
|
||||
ui\PasswordSetupDialog.class
|
||||
model\HighMaker.class
|
||||
model\QuestionMaker$1.class
|
||||
ui\RegisterDialog.class
|
||||
model\Student.class
|
||||
ui\LoginFrame.class
|
||||
ui\MathLearningApp.class
|
||||
model\Question.class
|
||||
model\MiddleMaker.class
|
||||
model\QuestionMaker$2.class
|
||||
ui\RegisterDialog$2.class
|
||||
@ -0,0 +1,17 @@
|
||||
E:\VSCode\Partner-Project\Math\src\model\MiddleMaker.java
|
||||
E:\VSCode\Partner-Project\Math\src\model\UserManager.java
|
||||
E:\VSCode\Partner-Project\Math\src\ui\RegisterDialog.java
|
||||
E:\VSCode\Partner-Project\Math\src\ui\ResultFrame.java
|
||||
E:\VSCode\Partner-Project\Math\src\model\Question.java
|
||||
E:\VSCode\Partner-Project\Math\src\model\Student.java
|
||||
E:\VSCode\Partner-Project\Math\src\model\QuestionMaker.java
|
||||
E:\VSCode\Partner-Project\Math\src\model\PrimaryMaker.java
|
||||
E:\VSCode\Partner-Project\Math\src\ui\PasswordSetupDialog.java
|
||||
E:\VSCode\Partner-Project\Math\src\ui\ChangePasswordDialog.java
|
||||
E:\VSCode\Partner-Project\Math\src\ui\MathLearningApp.java
|
||||
E:\VSCode\Partner-Project\Math\src\ui\GradeSelectionFrame.java
|
||||
E:\VSCode\Partner-Project\Math\src\ui\LoginFrame.java
|
||||
E:\VSCode\Partner-Project\Math\src\ui\QuizFrame.java
|
||||
E:\VSCode\Partner-Project\Math\src\model\Grade.java
|
||||
E:\VSCode\Partner-Project\Math\src\model\HighMaker.java
|
||||
E:\VSCode\Partner-Project\Math\src\ui\UserSettingsDialog.java
|
||||
@ -0,0 +1,14 @@
|
||||
{
|
||||
"3551664030@qq.com": {
|
||||
"email": "3551664030@qq.com",
|
||||
"password": "123456Ab",
|
||||
"grade": "primary",
|
||||
"username": "violet"
|
||||
},
|
||||
"2904255373@qq.com": {
|
||||
"email": "2904255373@qq.com",
|
||||
"password": "123456Ab",
|
||||
"grade": "primary",
|
||||
"username": "Violet"
|
||||
}
|
||||
}
|
||||
Loading…
Reference in new issue