合并到develop #5
Merged
hnu202326010321
merged 11 commits from chenchenghuan_branch into develop 4 months ago
@ -0,0 +1,21 @@
|
||||
import controller.NavigationController;
|
||||
import javax.swing.UIManager;
|
||||
import javax.swing.SwingUtilities;
|
||||
|
||||
public class MathLearningApp {
|
||||
public static void main(String[] args) {
|
||||
// Set system look and feel
|
||||
try {
|
||||
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
// Start the application
|
||||
SwingUtilities.invokeLater(() -> {
|
||||
// 获取 NavigationController 实例并显示登录界面
|
||||
NavigationController navigationController = NavigationController.getInstance();
|
||||
navigationController.showLoginView();
|
||||
});
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,127 @@
|
||||
package controller;
|
||||
|
||||
import model.User;
|
||||
import view.LoginView;
|
||||
import view.RegisterView;
|
||||
import view.MainView;
|
||||
import view.ExamView;
|
||||
import view.ResultView;
|
||||
|
||||
public class NavigationController extends BaseController implements NavigationService {
|
||||
private static NavigationController instance;
|
||||
private LoginView loginView;
|
||||
private RegisterView registerView;
|
||||
private MainView mainView;
|
||||
private ExamView examView;
|
||||
private ResultView resultView;
|
||||
private User currentUser;
|
||||
|
||||
// 单例模式
|
||||
public static NavigationController getInstance() {
|
||||
if (instance == null) {
|
||||
instance = new NavigationController();
|
||||
}
|
||||
return instance;
|
||||
}
|
||||
|
||||
private NavigationController() {
|
||||
// 私有构造函数
|
||||
}
|
||||
|
||||
@Override
|
||||
public void showLoginView() {
|
||||
if (loginView == null) {
|
||||
loginView = new LoginView();
|
||||
}
|
||||
loginView.setVisible(true);
|
||||
hideAllExcept(loginView);
|
||||
logInfo("显示登录界面");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void showRegisterView() {
|
||||
if (registerView == null) {
|
||||
registerView = new RegisterView();
|
||||
}
|
||||
registerView.setVisible(true);
|
||||
hideAllExcept(registerView);
|
||||
logInfo("显示注册界面");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void showMainView(User user) {
|
||||
setCurrentUser(user);
|
||||
if (mainView != null) {
|
||||
mainView.dispose();
|
||||
}
|
||||
mainView = new MainView(user);
|
||||
mainView.setVisible(true);
|
||||
hideAllExcept(mainView);
|
||||
logInfo("显示主界面 - 用户: " + user.getUsername());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void showMainView() {
|
||||
if (currentUser != null) {
|
||||
showMainView(currentUser);
|
||||
} else {
|
||||
showLoginView();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void showExamView(String difficulty, int questionCount) {
|
||||
try {
|
||||
validateStringNotEmpty(difficulty, "难度");
|
||||
if (questionCount <= 0) {
|
||||
throw new IllegalArgumentException("题目数量必须大于0");
|
||||
}
|
||||
|
||||
if (examView == null) {
|
||||
examView = new ExamView();
|
||||
}
|
||||
examView.startNewExam(difficulty, questionCount);
|
||||
examView.setVisible(true);
|
||||
hideAllExcept(examView);
|
||||
logInfo("显示考试界面 - " + difficulty + "难度, " + questionCount + "道题");
|
||||
} catch (Exception e) {
|
||||
logError("显示考试界面异常: " + e.getMessage());
|
||||
showError("无法开始考试: " + e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void showResultView(int score, int total, double percentage) {
|
||||
try {
|
||||
if (resultView == null) {
|
||||
resultView = new ResultView();
|
||||
}
|
||||
resultView.setResults(score, total, percentage);
|
||||
resultView.setVisible(true);
|
||||
hideAllExcept(resultView);
|
||||
logInfo("显示成绩界面 - 得分: " + score + "/" + total);
|
||||
} catch (Exception e) {
|
||||
logError("显示成绩界面异常: " + e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setCurrentUser(User user) {
|
||||
this.currentUser = user;
|
||||
logInfo("设置当前用户: " + (user != null ? user.getUsername() : "null"));
|
||||
}
|
||||
|
||||
@Override
|
||||
public User getCurrentUser() {
|
||||
return currentUser;
|
||||
}
|
||||
|
||||
private void hideAllExcept(javax.swing.JFrame visibleFrame) {
|
||||
javax.swing.JFrame[] frames = {loginView, registerView, mainView, examView, resultView};
|
||||
for (javax.swing.JFrame frame : frames) {
|
||||
if (frame != null && frame != visibleFrame) {
|
||||
frame.setVisible(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,14 @@
|
||||
package controller;
|
||||
|
||||
import model.User;
|
||||
|
||||
public interface NavigationService {
|
||||
void showLoginView();
|
||||
void showRegisterView();
|
||||
void showMainView(User user);
|
||||
void showMainView();
|
||||
void showExamView(String difficulty, int questionCount);
|
||||
void showResultView(int score, int total, double percentage);
|
||||
void setCurrentUser(User user);
|
||||
User getCurrentUser();
|
||||
}
|
||||
@ -0,0 +1,117 @@
|
||||
package controller;
|
||||
|
||||
import model.Question;
|
||||
import model.QuestionGenerator;
|
||||
import utils.FileUtil;
|
||||
import java.util.List;
|
||||
import java.util.Arrays;
|
||||
|
||||
public class QuestionController extends BaseController implements QuestionService {
|
||||
private QuestionGenerator generator = new QuestionGenerator();
|
||||
private List<Question> currentQuestions;
|
||||
private int currentQuestionIndex = 0;
|
||||
private int score = 0;
|
||||
private int[] userAnswers;
|
||||
private String currentDifficulty;
|
||||
private int currentQuestionCount;
|
||||
|
||||
@Override
|
||||
public void startNewExam(String difficulty, int questionCount) {
|
||||
try {
|
||||
validateStringNotEmpty(difficulty, "难度");
|
||||
if (questionCount <= 0 || questionCount > 100) {
|
||||
throw new IllegalArgumentException("题目数量必须在1-100之间");
|
||||
}
|
||||
|
||||
currentQuestions = generator.generateQuestions(questionCount, difficulty);
|
||||
currentQuestionIndex = 0;
|
||||
score = 0;
|
||||
userAnswers = new int[questionCount];
|
||||
Arrays.fill(userAnswers, -1);
|
||||
currentDifficulty = difficulty;
|
||||
currentQuestionCount = questionCount;
|
||||
|
||||
FileUtil.saveCurrentExam(currentQuestions, difficulty, questionCount);
|
||||
logInfo("生成新试卷: " + difficulty + " 难度, " + questionCount + " 道题");
|
||||
} catch (Exception e) {
|
||||
logError("开始新考试异常: " + e.getMessage());
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getCurrentExamInfo() {
|
||||
if (currentDifficulty != null && currentQuestionCount > 0) {
|
||||
return currentDifficulty + "难度 - " + currentQuestionCount + "道题";
|
||||
}
|
||||
return "暂无试卷";
|
||||
}
|
||||
|
||||
@Override
|
||||
public Question getCurrentQuestion() {
|
||||
if (currentQuestions == null || currentQuestionIndex >= currentQuestions.size()) {
|
||||
return null;
|
||||
}
|
||||
return currentQuestions.get(currentQuestionIndex);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void submitAnswer(int answer) {
|
||||
if (currentQuestionIndex < userAnswers.length) {
|
||||
userAnswers[currentQuestionIndex] = answer;
|
||||
logInfo("提交答案: 第" + getCurrentQuestionNumber() + "题, 答案: " + answer);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean nextQuestion() {
|
||||
currentQuestionIndex++;
|
||||
boolean hasNext = currentQuestionIndex < currentQuestions.size();
|
||||
logInfo("下一题: " + (hasNext ? "有" : "无"));
|
||||
return hasNext;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean previousQuestion() {
|
||||
if (currentQuestionIndex > 0) {
|
||||
currentQuestionIndex--;
|
||||
logInfo("上一题: 第" + getCurrentQuestionNumber() + "题");
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int calculateScore() {
|
||||
score = 0;
|
||||
for (int i = 0; i < currentQuestions.size(); i++) {
|
||||
if (userAnswers[i] != -1 && currentQuestions.get(i).isCorrect(userAnswers[i])) {
|
||||
score++;
|
||||
}
|
||||
}
|
||||
logInfo("计算得分: " + score + "/" + currentQuestions.size());
|
||||
return score;
|
||||
}
|
||||
|
||||
@Override
|
||||
public double getPercentage() {
|
||||
double percentage = (double) score / currentQuestions.size() * 100;
|
||||
logInfo("正确率: " + String.format("%.1f%%", percentage));
|
||||
return percentage;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getCurrentQuestionNumber() {
|
||||
return currentQuestionIndex + 1;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getTotalQuestions() {
|
||||
return currentQuestions != null ? currentQuestions.size() : 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getUserAnswerForCurrentQuestion() {
|
||||
return userAnswers[currentQuestionIndex];
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,17 @@
|
||||
package controller;
|
||||
|
||||
import model.Question;
|
||||
|
||||
public interface QuestionService {
|
||||
void startNewExam(String difficulty, int questionCount);
|
||||
Question getCurrentQuestion();
|
||||
void submitAnswer(int answer);
|
||||
boolean nextQuestion();
|
||||
boolean previousQuestion();
|
||||
int calculateScore();
|
||||
double getPercentage();
|
||||
int getCurrentQuestionNumber();
|
||||
int getTotalQuestions();
|
||||
int getUserAnswerForCurrentQuestion();
|
||||
String getCurrentExamInfo();
|
||||
}
|
||||
@ -0,0 +1,11 @@
|
||||
package controller;
|
||||
|
||||
import model.User;
|
||||
|
||||
public interface UserService {
|
||||
String registerUser(String username, String email);
|
||||
String completeRegistration(String username, String code, String password, String confirmPassword);
|
||||
User login(String loginId, String password);
|
||||
String changePassword(User user, String oldPassword, String newPassword, String confirmPassword);
|
||||
void cleanupUnregisteredUsers();
|
||||
}
|
||||
@ -0,0 +1,36 @@
|
||||
package model;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
public class Question implements Serializable {
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
private String question;
|
||||
private String[] options;
|
||||
private int correctAnswer;
|
||||
private String difficulty;
|
||||
|
||||
public Question(String question, String[] options, int correctAnswer, String difficulty) {
|
||||
this.question = question;
|
||||
this.options = options;
|
||||
this.correctAnswer = correctAnswer;
|
||||
this.difficulty = difficulty;
|
||||
}
|
||||
|
||||
// Getters
|
||||
public String getQuestion() { return question; }
|
||||
public String[] getOptions() { return options; }
|
||||
|
||||
|
||||
public boolean isCorrect(int selectedAnswer) {
|
||||
return selectedAnswer == correctAnswer;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "Question{" +
|
||||
"question='" + question + '\'' +
|
||||
", difficulty='" + difficulty + '\'' +
|
||||
'}';
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,30 @@
|
||||
package model;
|
||||
|
||||
public class User {
|
||||
private String username; // 新增:用户名
|
||||
private String email;
|
||||
private String password;
|
||||
private String registrationCode;
|
||||
private boolean isRegistered;
|
||||
|
||||
public User(String username, String email, String registrationCode) {
|
||||
this.username = username;
|
||||
this.email = email;
|
||||
this.registrationCode = registrationCode;
|
||||
this.isRegistered = false;
|
||||
}
|
||||
|
||||
// Getters and Setters
|
||||
public String getUsername() { return username; }
|
||||
public void setUsername(String username) { this.username = username; }
|
||||
|
||||
public String getEmail() { return email; }
|
||||
|
||||
public String getPassword() { return password; }
|
||||
public void setPassword(String password) { this.password = password; }
|
||||
|
||||
public String getRegistrationCode() { return registrationCode; }
|
||||
|
||||
public boolean isRegistered() { return isRegistered; }
|
||||
public void setRegistered(boolean registered) { isRegistered = registered; }
|
||||
}
|
||||
@ -0,0 +1,281 @@
|
||||
package view;
|
||||
|
||||
import controller.NavigationController;
|
||||
import controller.NavigationService;
|
||||
import controller.QuestionController;
|
||||
import model.Question;
|
||||
|
||||
import javax.swing.JFrame;
|
||||
import javax.swing.JPanel;
|
||||
import javax.swing.JLabel;
|
||||
import javax.swing.JRadioButton;
|
||||
import javax.swing.JButton;
|
||||
import javax.swing.ButtonGroup;
|
||||
import javax.swing.BorderFactory;
|
||||
import javax.swing.JOptionPane;
|
||||
import java.awt.BorderLayout;
|
||||
import java.awt.GridLayout;
|
||||
import java.awt.FlowLayout;
|
||||
import java.awt.Font;
|
||||
import java.awt.Color;
|
||||
import java.awt.event.ActionEvent;
|
||||
import java.awt.event.ActionListener;
|
||||
import java.awt.event.ItemEvent;
|
||||
import java.awt.event.ItemListener;
|
||||
|
||||
public class ExamView extends JFrame {
|
||||
private QuestionController questionController;
|
||||
private NavigationService navigationService;
|
||||
private JLabel questionLabel;
|
||||
private JLabel progressLabel;
|
||||
private ButtonGroup optionGroup;
|
||||
private JRadioButton[] optionButtons;
|
||||
private JButton prevButton;
|
||||
private JButton nextButton;
|
||||
private JButton submitButton;
|
||||
private JLabel hintLabel;
|
||||
|
||||
public ExamView() {
|
||||
questionController = new QuestionController();
|
||||
navigationService = NavigationController.getInstance();
|
||||
initializeUI();
|
||||
}
|
||||
|
||||
private void initializeUI() {
|
||||
setTitle("数学学习软件 - 答题界面");
|
||||
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
|
||||
setSize(600, 450);
|
||||
setLocationRelativeTo(null);
|
||||
setResizable(false);
|
||||
|
||||
JPanel mainPanel = new JPanel(new BorderLayout(10, 10));
|
||||
mainPanel.setBorder(BorderFactory.createEmptyBorder(20, 20, 20, 20));
|
||||
|
||||
// Progress label
|
||||
progressLabel = new JLabel("", JLabel.CENTER);
|
||||
progressLabel.setFont(new Font("微软雅黑", Font.BOLD, 16));
|
||||
mainPanel.add(progressLabel, BorderLayout.NORTH);
|
||||
|
||||
// Question panel
|
||||
JPanel questionPanel = new JPanel(new BorderLayout(10, 10));
|
||||
questionLabel = new JLabel("", JLabel.CENTER);
|
||||
questionLabel.setFont(new Font("微软雅黑", Font.PLAIN, 18));
|
||||
questionPanel.add(questionLabel, BorderLayout.NORTH);
|
||||
|
||||
// Options panel
|
||||
JPanel optionsPanel = new JPanel(new GridLayout(4, 1, 10, 10));
|
||||
optionGroup = new ButtonGroup();
|
||||
optionButtons = new JRadioButton[4];
|
||||
|
||||
for (int i = 0; i < 4; i++) {
|
||||
optionButtons[i] = new JRadioButton();
|
||||
optionButtons[i].setFont(new Font("微软雅黑", Font.PLAIN, 14));
|
||||
optionGroup.add(optionButtons[i]);
|
||||
optionsPanel.add(optionButtons[i]);
|
||||
|
||||
optionButtons[i].addItemListener(new OptionSelectionListener());
|
||||
}
|
||||
|
||||
questionPanel.add(optionsPanel, BorderLayout.CENTER);
|
||||
mainPanel.add(questionPanel, BorderLayout.CENTER);
|
||||
|
||||
// Hint label
|
||||
hintLabel = new JLabel("请选择答案后继续", JLabel.CENTER);
|
||||
hintLabel.setFont(new Font("微软雅黑", Font.PLAIN, 14));
|
||||
hintLabel.setForeground(Color.RED);
|
||||
hintLabel.setVisible(false);
|
||||
mainPanel.add(hintLabel, BorderLayout.SOUTH);
|
||||
|
||||
// Button panel
|
||||
JPanel buttonPanel = new JPanel(new FlowLayout());
|
||||
prevButton = new JButton("上一题");
|
||||
nextButton = new JButton("下一题");
|
||||
submitButton = new JButton("提交试卷");
|
||||
|
||||
prevButton.setFont(new Font("微软雅黑", Font.PLAIN, 14));
|
||||
nextButton.setFont(new Font("微软雅黑", Font.PLAIN, 14));
|
||||
submitButton.setFont(new Font("微软雅黑", Font.PLAIN, 14));
|
||||
|
||||
nextButton.setEnabled(false);
|
||||
|
||||
buttonPanel.add(prevButton);
|
||||
buttonPanel.add(nextButton);
|
||||
buttonPanel.add(submitButton);
|
||||
|
||||
mainPanel.add(buttonPanel, BorderLayout.SOUTH);
|
||||
|
||||
// Add action listeners
|
||||
prevButton.addActionListener(new PrevButtonAction());
|
||||
nextButton.addActionListener(new NextButtonAction());
|
||||
submitButton.addActionListener(new SubmitButtonAction());
|
||||
|
||||
add(mainPanel);
|
||||
}
|
||||
|
||||
public void startNewExam(String difficulty, int questionCount) {
|
||||
questionController.startNewExam(difficulty, questionCount);
|
||||
displayCurrentQuestion();
|
||||
updateNavigationButtons();
|
||||
updateNextButtonState();
|
||||
}
|
||||
|
||||
private void displayCurrentQuestion() {
|
||||
Question question = questionController.getCurrentQuestion();
|
||||
if (question == null) return;
|
||||
|
||||
progressLabel.setText(String.format("第 %d 题 / 共 %d 题",
|
||||
questionController.getCurrentQuestionNumber(),
|
||||
questionController.getTotalQuestions()));
|
||||
|
||||
questionLabel.setText(question.getQuestion());
|
||||
|
||||
String[] options = question.getOptions();
|
||||
for (int i = 0; i < 4; i++) {
|
||||
optionButtons[i].setText((char)('A' + i) + ". " + options[i]);
|
||||
}
|
||||
|
||||
// Restore user's previous selection
|
||||
int userAnswer = questionController.getUserAnswerForCurrentQuestion();
|
||||
optionGroup.clearSelection();
|
||||
if (userAnswer != -1) {
|
||||
optionButtons[userAnswer].setSelected(true);
|
||||
nextButton.setEnabled(canGoNext());
|
||||
hintLabel.setVisible(false);
|
||||
} else {
|
||||
nextButton.setEnabled(false);
|
||||
}
|
||||
}
|
||||
|
||||
private void updateNavigationButtons() {
|
||||
int current = questionController.getCurrentQuestionNumber();
|
||||
int total = questionController.getTotalQuestions();
|
||||
|
||||
prevButton.setEnabled(current > 1);
|
||||
|
||||
// 修改这里:最后一题时禁用下一题按钮
|
||||
boolean isLastQuestion = current == total;
|
||||
nextButton.setEnabled(!isLastQuestion && isCurrentQuestionAnswered());
|
||||
submitButton.setEnabled(isLastQuestion && isCurrentQuestionAnswered());
|
||||
}
|
||||
|
||||
private void updateNextButtonState() {
|
||||
boolean isLastQuestion = questionController.getCurrentQuestionNumber() == questionController.getTotalQuestions();
|
||||
|
||||
if (isLastQuestion) {
|
||||
// 最后一题:禁用下一题,启用提交按钮(如果已回答)
|
||||
nextButton.setEnabled(false);
|
||||
submitButton.setEnabled(isCurrentQuestionAnswered());
|
||||
} else {
|
||||
// 不是最后一题:根据是否回答控制下一题按钮
|
||||
nextButton.setEnabled(isCurrentQuestionAnswered());
|
||||
submitButton.setEnabled(false);
|
||||
}
|
||||
|
||||
hintLabel.setVisible(!isCurrentQuestionAnswered());
|
||||
}
|
||||
|
||||
private boolean canGoNext() {
|
||||
int current = questionController.getCurrentQuestionNumber();
|
||||
int total = questionController.getTotalQuestions();
|
||||
return current < total && isCurrentQuestionAnswered();
|
||||
}
|
||||
|
||||
private boolean isCurrentQuestionAnswered() {
|
||||
for (int i = 0; i < 4; i++) {
|
||||
if (optionButtons[i].isSelected()) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private void saveCurrentAnswer() {
|
||||
for (int i = 0; i < 4; i++) {
|
||||
if (optionButtons[i].isSelected()) {
|
||||
questionController.submitAnswer(i);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 选项选择监听器
|
||||
private class OptionSelectionListener implements ItemListener {
|
||||
@Override
|
||||
public void itemStateChanged(ItemEvent e) {
|
||||
if (e.getStateChange() == ItemEvent.SELECTED) {
|
||||
saveCurrentAnswer(); // 立即保存答案
|
||||
updateNextButtonState();
|
||||
updateNavigationButtons();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private class PrevButtonAction implements ActionListener {
|
||||
@Override
|
||||
public void actionPerformed(ActionEvent e) {
|
||||
saveCurrentAnswer();
|
||||
if (questionController.previousQuestion()) {
|
||||
displayCurrentQuestion();
|
||||
updateNavigationButtons();
|
||||
updateNextButtonState();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private class NextButtonAction implements ActionListener {
|
||||
@Override
|
||||
public void actionPerformed(ActionEvent e) {
|
||||
int current = questionController.getCurrentQuestionNumber();
|
||||
int total = questionController.getTotalQuestions();
|
||||
|
||||
// 检查是否是最后一题
|
||||
if (current >= total) {
|
||||
JOptionPane.showMessageDialog(ExamView.this,
|
||||
"已经是最后一题了,请点击提交试卷!", "提示",
|
||||
JOptionPane.INFORMATION_MESSAGE);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!isCurrentQuestionAnswered()) {
|
||||
JOptionPane.showMessageDialog(ExamView.this,
|
||||
"请先选择答案!", "提示", JOptionPane.WARNING_MESSAGE);
|
||||
return;
|
||||
}
|
||||
|
||||
saveCurrentAnswer();
|
||||
if (questionController.nextQuestion()) {
|
||||
displayCurrentQuestion();
|
||||
updateNavigationButtons();
|
||||
updateNextButtonState();
|
||||
} else {
|
||||
// 如果无法切换到下一题,可能是最后一题
|
||||
JOptionPane.showMessageDialog(ExamView.this,
|
||||
"无法切换到下一题,请点击提交试卷!", "提示",
|
||||
JOptionPane.INFORMATION_MESSAGE);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private class SubmitButtonAction implements ActionListener {
|
||||
@Override
|
||||
public void actionPerformed(ActionEvent e) {
|
||||
if (!isCurrentQuestionAnswered()) {
|
||||
JOptionPane.showMessageDialog(ExamView.this,
|
||||
"请先完成本题!", "提示", JOptionPane.WARNING_MESSAGE);
|
||||
return;
|
||||
}
|
||||
|
||||
saveCurrentAnswer();
|
||||
|
||||
int score = questionController.calculateScore();
|
||||
int total = questionController.getTotalQuestions();
|
||||
double percentage = questionController.getPercentage();
|
||||
|
||||
// 关闭当前窗口
|
||||
dispose();
|
||||
|
||||
// 显示结果页面
|
||||
navigationService.showResultView(score, total, percentage); // 修改
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,130 @@
|
||||
package view;
|
||||
|
||||
import controller.NavigationController;
|
||||
import controller.NavigationService;
|
||||
import controller.UserController;
|
||||
import controller.UserService;
|
||||
import model.User;
|
||||
|
||||
import javax.swing.JFrame;
|
||||
import javax.swing.JPanel;
|
||||
import javax.swing.JLabel;
|
||||
import javax.swing.JTextField;
|
||||
import javax.swing.JPasswordField;
|
||||
import javax.swing.JButton;
|
||||
import javax.swing.BorderFactory;
|
||||
import javax.swing.JOptionPane;
|
||||
import java.awt.BorderLayout;
|
||||
import java.awt.GridLayout;
|
||||
import java.awt.FlowLayout;
|
||||
import java.awt.Font;
|
||||
import java.awt.event.ActionEvent;
|
||||
import java.awt.event.ActionListener;
|
||||
|
||||
public class LoginView extends JFrame {
|
||||
private JTextField usernameField;
|
||||
private JPasswordField passwordField;
|
||||
private UserService userController;
|
||||
private NavigationService navigationService;
|
||||
|
||||
public LoginView() {
|
||||
userController = new UserController();
|
||||
navigationService = NavigationController.getInstance();
|
||||
initializeUI();
|
||||
cleanupUnregisteredUsers();
|
||||
}
|
||||
|
||||
private void cleanupUnregisteredUsers() {
|
||||
try {
|
||||
userController.cleanupUnregisteredUsers();
|
||||
} catch (Exception e) {
|
||||
System.err.println("清理未注册用户时出错: " + e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
private void initializeUI() {
|
||||
setTitle("数学学习软件 - 登录");
|
||||
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
|
||||
setSize(400, 300);
|
||||
setLocationRelativeTo(null);
|
||||
setResizable(false);
|
||||
|
||||
JPanel mainPanel = new JPanel(new BorderLayout(10, 10));
|
||||
mainPanel.setBorder(BorderFactory.createEmptyBorder(20, 20, 20, 20));
|
||||
|
||||
// Title
|
||||
JLabel titleLabel = new JLabel("用户登录", JLabel.CENTER);
|
||||
titleLabel.setFont(new Font("微软雅黑", Font.BOLD, 24));
|
||||
mainPanel.add(titleLabel, BorderLayout.NORTH);
|
||||
|
||||
// Form panel
|
||||
JPanel formPanel = new JPanel(new GridLayout(3, 2, 10, 10));
|
||||
|
||||
JLabel usernameLabel = new JLabel("用户名:");
|
||||
usernameLabel.setFont(new Font("微软雅黑", Font.PLAIN, 14));
|
||||
usernameField = new JTextField();
|
||||
|
||||
JLabel passwordLabel = new JLabel("密码:");
|
||||
passwordLabel.setFont(new Font("微软雅黑", Font.PLAIN, 14));
|
||||
passwordField = new JPasswordField();
|
||||
|
||||
formPanel.add(usernameLabel);
|
||||
formPanel.add(usernameField);
|
||||
formPanel.add(passwordLabel);
|
||||
formPanel.add(passwordField);
|
||||
|
||||
// Buttons
|
||||
JPanel buttonPanel = new JPanel(new FlowLayout());
|
||||
JButton loginButton = new JButton("登录");
|
||||
JButton registerButton = new JButton("注册");
|
||||
|
||||
loginButton.setFont(new Font("微软雅黑", Font.PLAIN, 14));
|
||||
registerButton.setFont(new Font("微软雅黑", Font.PLAIN, 14));
|
||||
|
||||
buttonPanel.add(loginButton);
|
||||
buttonPanel.add(registerButton);
|
||||
|
||||
formPanel.add(new JLabel()); // Empty cell
|
||||
formPanel.add(buttonPanel);
|
||||
|
||||
mainPanel.add(formPanel, BorderLayout.CENTER);
|
||||
|
||||
// Add action listeners
|
||||
loginButton.addActionListener(new LoginAction());
|
||||
registerButton.addActionListener(e -> {
|
||||
|
||||
navigationService.showRegisterView();
|
||||
});
|
||||
|
||||
// Enter key support
|
||||
usernameField.addActionListener(new LoginAction());
|
||||
passwordField.addActionListener(new LoginAction());
|
||||
|
||||
add(mainPanel);
|
||||
}
|
||||
|
||||
private class LoginAction implements ActionListener {
|
||||
@Override
|
||||
public void actionPerformed(ActionEvent e) {
|
||||
String username = usernameField.getText().trim();
|
||||
String password = new String(passwordField.getPassword());
|
||||
|
||||
if (username.isEmpty() || password.isEmpty()) {
|
||||
JOptionPane.showMessageDialog(LoginView.this,
|
||||
"请输入用户名和密码", "错误", JOptionPane.ERROR_MESSAGE);
|
||||
return;
|
||||
}
|
||||
|
||||
User user = userController.login(username, password);
|
||||
if (user != null) {
|
||||
JOptionPane.showMessageDialog(LoginView.this,
|
||||
"登录成功!", "成功", JOptionPane.INFORMATION_MESSAGE);
|
||||
|
||||
navigationService.showMainView(user);
|
||||
} else {
|
||||
JOptionPane.showMessageDialog(LoginView.this,
|
||||
"用户名或密码错误", "错误", JOptionPane.ERROR_MESSAGE);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,164 @@
|
||||
package view;
|
||||
|
||||
import controller.NavigationController;
|
||||
import controller.NavigationService;
|
||||
import controller.UserController;
|
||||
import model.User;
|
||||
|
||||
import javax.swing.JFrame;
|
||||
import javax.swing.JPanel;
|
||||
import javax.swing.JLabel;
|
||||
import javax.swing.JTextField;
|
||||
import javax.swing.JPasswordField;
|
||||
import javax.swing.JButton;
|
||||
import javax.swing.BorderFactory;
|
||||
import javax.swing.JOptionPane;
|
||||
import java.awt.BorderLayout;
|
||||
import java.awt.GridLayout;
|
||||
import java.awt.FlowLayout;
|
||||
import java.awt.Font;
|
||||
import java.awt.event.ActionEvent;
|
||||
import java.awt.event.ActionListener;
|
||||
|
||||
public class RegisterView extends JFrame {
|
||||
private JTextField usernameField; // 用户名输入框
|
||||
private JTextField emailField;
|
||||
private JTextField codeField;
|
||||
private JPasswordField passwordField;
|
||||
private JPasswordField confirmPasswordField;
|
||||
private UserController userController;
|
||||
private NavigationService navigationService; // 新增
|
||||
private String currentUsername; // 保存当前注册的用户名
|
||||
|
||||
public RegisterView() {
|
||||
userController = new UserController();
|
||||
navigationService = NavigationController.getInstance(); // 新增
|
||||
initializeUI();
|
||||
}
|
||||
|
||||
private void initializeUI() {
|
||||
setTitle("数学学习软件 - 注册");
|
||||
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
|
||||
setSize(550, 500);
|
||||
setLocationRelativeTo(null);
|
||||
setResizable(false);
|
||||
|
||||
JPanel mainPanel = new JPanel(new BorderLayout(10, 10));
|
||||
mainPanel.setBorder(BorderFactory.createEmptyBorder(20, 20, 20, 20));
|
||||
|
||||
// Title
|
||||
JLabel titleLabel = new JLabel("用户注册", JLabel.CENTER);
|
||||
titleLabel.setFont(new Font("微软雅黑", Font.BOLD, 24));
|
||||
mainPanel.add(titleLabel, BorderLayout.NORTH);
|
||||
|
||||
// Form panel - 增加用户名字段
|
||||
JPanel formPanel = new JPanel(new GridLayout(8, 2, 10, 10));
|
||||
|
||||
JLabel usernameLabel = new JLabel("用户名:");
|
||||
usernameLabel.setFont(new Font("微软雅黑", Font.PLAIN, 14));
|
||||
usernameField = new JTextField();
|
||||
|
||||
JLabel emailLabel = new JLabel("邮箱:");
|
||||
emailLabel.setFont(new Font("微软雅黑", Font.PLAIN, 14));
|
||||
emailField = new JTextField();
|
||||
|
||||
JLabel codeLabel = new JLabel("注册码:");
|
||||
codeLabel.setFont(new Font("微软雅黑", Font.PLAIN, 14));
|
||||
codeField = new JTextField();
|
||||
|
||||
JLabel passwordLabel = new JLabel("密码:");
|
||||
passwordLabel.setFont(new Font("微软雅黑", Font.PLAIN, 14));
|
||||
passwordField = new JPasswordField();
|
||||
|
||||
JLabel confirmPasswordLabel = new JLabel("确认密码:");
|
||||
confirmPasswordLabel.setFont(new Font("微软雅黑", Font.PLAIN, 14));
|
||||
confirmPasswordField = new JPasswordField();
|
||||
|
||||
JButton sendCodeButton = new JButton("发送注册码");
|
||||
sendCodeButton.setFont(new Font("微软雅黑", Font.PLAIN, 12));
|
||||
|
||||
JButton registerButton = new JButton("完成注册");
|
||||
registerButton.setFont(new Font("微软雅黑", Font.PLAIN, 14));
|
||||
|
||||
// 布局表单
|
||||
formPanel.add(usernameLabel);
|
||||
formPanel.add(usernameField);
|
||||
formPanel.add(emailLabel);
|
||||
formPanel.add(emailField);
|
||||
formPanel.add(sendCodeButton);
|
||||
formPanel.add(new JLabel());
|
||||
formPanel.add(codeLabel);
|
||||
formPanel.add(codeField);
|
||||
formPanel.add(passwordLabel);
|
||||
formPanel.add(passwordField);
|
||||
formPanel.add(confirmPasswordLabel);
|
||||
formPanel.add(confirmPasswordField);
|
||||
|
||||
formPanel.add(registerButton);
|
||||
|
||||
mainPanel.add(formPanel, BorderLayout.CENTER);
|
||||
|
||||
// Back button
|
||||
JButton backButton = new JButton("返回登录");
|
||||
backButton.setFont(new Font("微软雅黑", Font.PLAIN, 14));
|
||||
backButton.addActionListener(e -> navigationService.showLoginView()); // 修改
|
||||
|
||||
JPanel bottomPanel = new JPanel(new FlowLayout());
|
||||
bottomPanel.add(backButton);
|
||||
mainPanel.add(bottomPanel, BorderLayout.SOUTH);
|
||||
|
||||
// Add action listeners
|
||||
sendCodeButton.addActionListener(new SendCodeAction());
|
||||
registerButton.addActionListener(new RegisterAction());
|
||||
|
||||
add(mainPanel);
|
||||
}
|
||||
|
||||
private class SendCodeAction implements ActionListener {
|
||||
@Override
|
||||
public void actionPerformed(ActionEvent e) {
|
||||
String username = usernameField.getText().trim();
|
||||
String email = emailField.getText().trim();
|
||||
|
||||
if (username.isEmpty() || email.isEmpty()) {
|
||||
JOptionPane.showMessageDialog(RegisterView.this,
|
||||
"请输入用户名和邮箱", "错误", JOptionPane.ERROR_MESSAGE);
|
||||
return;
|
||||
}
|
||||
|
||||
String result = userController.registerUser(username, email);
|
||||
JOptionPane.showMessageDialog(RegisterView.this, result);
|
||||
|
||||
if (result.contains("发送")) {
|
||||
currentUsername = username;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private class RegisterAction implements ActionListener {
|
||||
@Override
|
||||
public void actionPerformed(ActionEvent e) {
|
||||
String username = usernameField.getText().trim();
|
||||
String code = codeField.getText().trim();
|
||||
String password = new String(passwordField.getPassword());
|
||||
String confirmPassword = new String(confirmPasswordField.getPassword());
|
||||
|
||||
if (username.isEmpty() || code.isEmpty() || password.isEmpty() || confirmPassword.isEmpty()) {
|
||||
JOptionPane.showMessageDialog(RegisterView.this,
|
||||
"请填写所有字段", "错误", JOptionPane.ERROR_MESSAGE);
|
||||
return;
|
||||
}
|
||||
|
||||
String result = userController.completeRegistration(username, code, password, confirmPassword);
|
||||
|
||||
if (result.equals("注册成功!")) {
|
||||
JOptionPane.showMessageDialog(RegisterView.this,
|
||||
result, "成功", JOptionPane.INFORMATION_MESSAGE);
|
||||
navigationService.showLoginView(); // 修改
|
||||
} else {
|
||||
JOptionPane.showMessageDialog(RegisterView.this,
|
||||
result, "错误", JOptionPane.ERROR_MESSAGE);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,79 @@
|
||||
package view;
|
||||
|
||||
import controller.NavigationController;
|
||||
import controller.NavigationService;
|
||||
|
||||
import javax.swing.JFrame;
|
||||
import javax.swing.JPanel;
|
||||
import javax.swing.JLabel;
|
||||
import javax.swing.JButton;
|
||||
import javax.swing.BorderFactory;
|
||||
import java.awt.BorderLayout;
|
||||
import java.awt.GridLayout;
|
||||
import java.awt.FlowLayout;
|
||||
import java.awt.Font;
|
||||
import java.awt.event.ActionEvent;
|
||||
import java.awt.event.ActionListener;
|
||||
|
||||
public class ResultView extends JFrame {
|
||||
private JLabel scoreLabel;
|
||||
private JLabel percentageLabel;
|
||||
private NavigationService navigationService;
|
||||
|
||||
public ResultView() {
|
||||
navigationService = NavigationController.getInstance(); // 新增
|
||||
initializeUI();
|
||||
}
|
||||
|
||||
private void initializeUI() {
|
||||
setTitle("数学学习软件 - 成绩界面");
|
||||
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
|
||||
setSize(400, 300);
|
||||
setLocationRelativeTo(null);
|
||||
setResizable(false);
|
||||
|
||||
JPanel mainPanel = new JPanel(new BorderLayout(10, 10));
|
||||
mainPanel.setBorder(BorderFactory.createEmptyBorder(20, 20, 20, 20));
|
||||
|
||||
// Title
|
||||
JLabel titleLabel = new JLabel("考试结果", JLabel.CENTER);
|
||||
titleLabel.setFont(new Font("微软雅黑", Font.BOLD, 24));
|
||||
mainPanel.add(titleLabel, BorderLayout.NORTH);
|
||||
|
||||
// Result panel
|
||||
JPanel resultPanel = new JPanel(new GridLayout(2, 1, 10, 10));
|
||||
|
||||
scoreLabel = new JLabel("", JLabel.CENTER);
|
||||
scoreLabel.setFont(new Font("微软雅黑", Font.PLAIN, 18));
|
||||
|
||||
percentageLabel = new JLabel("", JLabel.CENTER);
|
||||
percentageLabel.setFont(new Font("微软雅黑", Font.PLAIN, 18));
|
||||
|
||||
resultPanel.add(scoreLabel);
|
||||
resultPanel.add(percentageLabel);
|
||||
mainPanel.add(resultPanel, BorderLayout.CENTER);
|
||||
|
||||
// Button panel
|
||||
JPanel buttonPanel = new JPanel(new FlowLayout());
|
||||
JButton continueButton = new JButton("继续做题");
|
||||
JButton exitButton = new JButton("退出系统");
|
||||
|
||||
continueButton.setFont(new Font("微软雅黑", Font.PLAIN, 14));
|
||||
exitButton.setFont(new Font("微软雅黑", Font.PLAIN, 14));
|
||||
|
||||
buttonPanel.add(continueButton);
|
||||
buttonPanel.add(exitButton);
|
||||
mainPanel.add(buttonPanel, BorderLayout.SOUTH);
|
||||
|
||||
// Add action listeners
|
||||
continueButton.addActionListener(e -> navigationService.showMainView()); // 修改
|
||||
exitButton.addActionListener(e -> System.exit(0));
|
||||
|
||||
add(mainPanel);
|
||||
}
|
||||
|
||||
public void setResults(int score, int total, double percentage) {
|
||||
scoreLabel.setText(String.format("得分: %d / %d", score, total));
|
||||
percentageLabel.setText(String.format("正确率: %.1f%%", percentage));
|
||||
}
|
||||
}
|
||||
Loading…
Reference in new issue