@ -0,0 +1,124 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="Palette2">
|
||||
<group name="Swing">
|
||||
<item class="com.intellij.uiDesigner.HSpacer" tooltip-text="Horizontal Spacer" icon="/com/intellij/uiDesigner/icons/hspacer.svg" removable="false" auto-create-binding="false" can-attach-label="false">
|
||||
<default-constraints vsize-policy="1" hsize-policy="6" anchor="0" fill="1" />
|
||||
</item>
|
||||
<item class="com.intellij.uiDesigner.VSpacer" tooltip-text="Vertical Spacer" icon="/com/intellij/uiDesigner/icons/vspacer.svg" removable="false" auto-create-binding="false" can-attach-label="false">
|
||||
<default-constraints vsize-policy="6" hsize-policy="1" anchor="0" fill="2" />
|
||||
</item>
|
||||
<item class="javax.swing.JPanel" icon="/com/intellij/uiDesigner/icons/panel.svg" removable="false" auto-create-binding="false" can-attach-label="false">
|
||||
<default-constraints vsize-policy="3" hsize-policy="3" anchor="0" fill="3" />
|
||||
</item>
|
||||
<item class="javax.swing.JScrollPane" icon="/com/intellij/uiDesigner/icons/scrollPane.svg" removable="false" auto-create-binding="false" can-attach-label="true">
|
||||
<default-constraints vsize-policy="7" hsize-policy="7" anchor="0" fill="3" />
|
||||
</item>
|
||||
<item class="javax.swing.JButton" icon="/com/intellij/uiDesigner/icons/button.svg" removable="false" auto-create-binding="true" can-attach-label="false">
|
||||
<default-constraints vsize-policy="0" hsize-policy="3" anchor="0" fill="1" />
|
||||
<initial-values>
|
||||
<property name="text" value="Button" />
|
||||
</initial-values>
|
||||
</item>
|
||||
<item class="javax.swing.JRadioButton" icon="/com/intellij/uiDesigner/icons/radioButton.svg" removable="false" auto-create-binding="true" can-attach-label="false">
|
||||
<default-constraints vsize-policy="0" hsize-policy="3" anchor="8" fill="0" />
|
||||
<initial-values>
|
||||
<property name="text" value="RadioButton" />
|
||||
</initial-values>
|
||||
</item>
|
||||
<item class="javax.swing.JCheckBox" icon="/com/intellij/uiDesigner/icons/checkBox.svg" removable="false" auto-create-binding="true" can-attach-label="false">
|
||||
<default-constraints vsize-policy="0" hsize-policy="3" anchor="8" fill="0" />
|
||||
<initial-values>
|
||||
<property name="text" value="CheckBox" />
|
||||
</initial-values>
|
||||
</item>
|
||||
<item class="javax.swing.JLabel" icon="/com/intellij/uiDesigner/icons/label.svg" removable="false" auto-create-binding="false" can-attach-label="false">
|
||||
<default-constraints vsize-policy="0" hsize-policy="0" anchor="8" fill="0" />
|
||||
<initial-values>
|
||||
<property name="text" value="Label" />
|
||||
</initial-values>
|
||||
</item>
|
||||
<item class="javax.swing.JTextField" icon="/com/intellij/uiDesigner/icons/textField.svg" removable="false" auto-create-binding="true" can-attach-label="true">
|
||||
<default-constraints vsize-policy="0" hsize-policy="6" anchor="8" fill="1">
|
||||
<preferred-size width="150" height="-1" />
|
||||
</default-constraints>
|
||||
</item>
|
||||
<item class="javax.swing.JPasswordField" icon="/com/intellij/uiDesigner/icons/passwordField.svg" removable="false" auto-create-binding="true" can-attach-label="true">
|
||||
<default-constraints vsize-policy="0" hsize-policy="6" anchor="8" fill="1">
|
||||
<preferred-size width="150" height="-1" />
|
||||
</default-constraints>
|
||||
</item>
|
||||
<item class="javax.swing.JFormattedTextField" icon="/com/intellij/uiDesigner/icons/formattedTextField.svg" removable="false" auto-create-binding="true" can-attach-label="true">
|
||||
<default-constraints vsize-policy="0" hsize-policy="6" anchor="8" fill="1">
|
||||
<preferred-size width="150" height="-1" />
|
||||
</default-constraints>
|
||||
</item>
|
||||
<item class="javax.swing.JTextArea" icon="/com/intellij/uiDesigner/icons/textArea.svg" removable="false" auto-create-binding="true" can-attach-label="true">
|
||||
<default-constraints vsize-policy="6" hsize-policy="6" anchor="0" fill="3">
|
||||
<preferred-size width="150" height="50" />
|
||||
</default-constraints>
|
||||
</item>
|
||||
<item class="javax.swing.JTextPane" icon="/com/intellij/uiDesigner/icons/textPane.svg" removable="false" auto-create-binding="true" can-attach-label="true">
|
||||
<default-constraints vsize-policy="6" hsize-policy="6" anchor="0" fill="3">
|
||||
<preferred-size width="150" height="50" />
|
||||
</default-constraints>
|
||||
</item>
|
||||
<item class="javax.swing.JEditorPane" icon="/com/intellij/uiDesigner/icons/editorPane.svg" removable="false" auto-create-binding="true" can-attach-label="true">
|
||||
<default-constraints vsize-policy="6" hsize-policy="6" anchor="0" fill="3">
|
||||
<preferred-size width="150" height="50" />
|
||||
</default-constraints>
|
||||
</item>
|
||||
<item class="javax.swing.JComboBox" icon="/com/intellij/uiDesigner/icons/comboBox.svg" removable="false" auto-create-binding="true" can-attach-label="true">
|
||||
<default-constraints vsize-policy="0" hsize-policy="2" anchor="8" fill="1" />
|
||||
</item>
|
||||
<item class="javax.swing.JTable" icon="/com/intellij/uiDesigner/icons/table.svg" removable="false" auto-create-binding="true" can-attach-label="false">
|
||||
<default-constraints vsize-policy="6" hsize-policy="6" anchor="0" fill="3">
|
||||
<preferred-size width="150" height="50" />
|
||||
</default-constraints>
|
||||
</item>
|
||||
<item class="javax.swing.JList" icon="/com/intellij/uiDesigner/icons/list.svg" removable="false" auto-create-binding="true" can-attach-label="false">
|
||||
<default-constraints vsize-policy="6" hsize-policy="2" anchor="0" fill="3">
|
||||
<preferred-size width="150" height="50" />
|
||||
</default-constraints>
|
||||
</item>
|
||||
<item class="javax.swing.JTree" icon="/com/intellij/uiDesigner/icons/tree.svg" removable="false" auto-create-binding="true" can-attach-label="false">
|
||||
<default-constraints vsize-policy="6" hsize-policy="6" anchor="0" fill="3">
|
||||
<preferred-size width="150" height="50" />
|
||||
</default-constraints>
|
||||
</item>
|
||||
<item class="javax.swing.JTabbedPane" icon="/com/intellij/uiDesigner/icons/tabbedPane.svg" removable="false" auto-create-binding="true" can-attach-label="false">
|
||||
<default-constraints vsize-policy="3" hsize-policy="3" anchor="0" fill="3">
|
||||
<preferred-size width="200" height="200" />
|
||||
</default-constraints>
|
||||
</item>
|
||||
<item class="javax.swing.JSplitPane" icon="/com/intellij/uiDesigner/icons/splitPane.svg" removable="false" auto-create-binding="false" can-attach-label="false">
|
||||
<default-constraints vsize-policy="3" hsize-policy="3" anchor="0" fill="3">
|
||||
<preferred-size width="200" height="200" />
|
||||
</default-constraints>
|
||||
</item>
|
||||
<item class="javax.swing.JSpinner" icon="/com/intellij/uiDesigner/icons/spinner.svg" removable="false" auto-create-binding="true" can-attach-label="true">
|
||||
<default-constraints vsize-policy="0" hsize-policy="6" anchor="8" fill="1" />
|
||||
</item>
|
||||
<item class="javax.swing.JSlider" icon="/com/intellij/uiDesigner/icons/slider.svg" removable="false" auto-create-binding="true" can-attach-label="false">
|
||||
<default-constraints vsize-policy="0" hsize-policy="6" anchor="8" fill="1" />
|
||||
</item>
|
||||
<item class="javax.swing.JSeparator" icon="/com/intellij/uiDesigner/icons/separator.svg" removable="false" auto-create-binding="false" can-attach-label="false">
|
||||
<default-constraints vsize-policy="6" hsize-policy="6" anchor="0" fill="3" />
|
||||
</item>
|
||||
<item class="javax.swing.JProgressBar" icon="/com/intellij/uiDesigner/icons/progressbar.svg" removable="false" auto-create-binding="true" can-attach-label="false">
|
||||
<default-constraints vsize-policy="0" hsize-policy="6" anchor="0" fill="1" />
|
||||
</item>
|
||||
<item class="javax.swing.JToolBar" icon="/com/intellij/uiDesigner/icons/toolbar.svg" removable="false" auto-create-binding="false" can-attach-label="false">
|
||||
<default-constraints vsize-policy="0" hsize-policy="6" anchor="0" fill="1">
|
||||
<preferred-size width="-1" height="20" />
|
||||
</default-constraints>
|
||||
</item>
|
||||
<item class="javax.swing.JToolBar$Separator" icon="/com/intellij/uiDesigner/icons/toolbarSeparator.svg" removable="false" auto-create-binding="false" can-attach-label="false">
|
||||
<default-constraints vsize-policy="0" hsize-policy="0" anchor="0" fill="1" />
|
||||
</item>
|
||||
<item class="javax.swing.JScrollBar" icon="/com/intellij/uiDesigner/icons/scrollbar.svg" removable="false" auto-create-binding="true" can-attach-label="false">
|
||||
<default-constraints vsize-policy="6" hsize-policy="0" anchor="0" fill="2" />
|
||||
</item>
|
||||
</group>
|
||||
</component>
|
||||
</project>
|
||||
|
After Width: | Height: | Size: 2.2 KiB |
@ -0,0 +1,17 @@
|
||||
package com.wsf.mathapp;
|
||||
|
||||
import com.wsf.mathapp.controller.SceneManager;
|
||||
import javafx.application.Application;
|
||||
import javafx.stage.Stage;
|
||||
|
||||
public class Main extends Application {
|
||||
@Override
|
||||
public void start(Stage primaryStage) {
|
||||
SceneManager sceneManager = new SceneManager(primaryStage);
|
||||
sceneManager.showLoginView();
|
||||
}
|
||||
|
||||
public static void main(String[] args) {
|
||||
launch(args);
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,84 @@
|
||||
package com.wsf.mathapp.controller;
|
||||
|
||||
import com.wsf.mathapp.view.*;
|
||||
import javafx.stage.Stage;
|
||||
|
||||
public class SceneManager {
|
||||
private final Stage primaryStage;
|
||||
private final LoginView loginView;
|
||||
private final RegisterView registerView;
|
||||
private final MainMenuView mainMenuView;
|
||||
private final LevelSelectionView levelSelectionView;
|
||||
private final QuestionCountView questionCountView;
|
||||
private final QuizView quizView;
|
||||
private final ResultView resultView;
|
||||
private String currentUserName;
|
||||
|
||||
public SceneManager(Stage primaryStage) {
|
||||
this.primaryStage = primaryStage;
|
||||
this.primaryStage.setTitle("数学学习软件");
|
||||
this.primaryStage.setResizable(false);
|
||||
|
||||
// 初始化所有视图
|
||||
this.loginView = new LoginView(this);
|
||||
this.registerView = new RegisterView(this);
|
||||
this.mainMenuView = new MainMenuView(this);
|
||||
this.levelSelectionView = new LevelSelectionView(this);
|
||||
this.questionCountView = new QuestionCountView(this);
|
||||
this.quizView = new QuizView(this);
|
||||
this.resultView = new ResultView(this);
|
||||
}
|
||||
|
||||
public void showLoginView() {
|
||||
primaryStage.setScene(loginView.getScene());
|
||||
primaryStage.show();
|
||||
}
|
||||
|
||||
public void showRegisterView() {
|
||||
primaryStage.setScene(registerView.getScene());
|
||||
primaryStage.show();
|
||||
}
|
||||
|
||||
public void showMainMenuView() {
|
||||
// 在显示主菜单前更新用户名
|
||||
if (mainMenuView != null) {
|
||||
mainMenuView.updateUsername(currentUserName);
|
||||
}
|
||||
if (mainMenuView != null) {
|
||||
primaryStage.setScene(mainMenuView.getScene());
|
||||
}
|
||||
}
|
||||
|
||||
public void showLevelSelectionView() {
|
||||
// 在显示级别选择界面前更新用户名
|
||||
if (levelSelectionView != null) {
|
||||
levelSelectionView.updateUsername(currentUserName);
|
||||
}
|
||||
if (levelSelectionView != null) {
|
||||
primaryStage.setScene(levelSelectionView.getScene());
|
||||
}
|
||||
}
|
||||
public void showQuestionCountView() {
|
||||
primaryStage.setScene(questionCountView.getScene());
|
||||
}
|
||||
|
||||
public void showQuizView() {
|
||||
primaryStage.setScene(quizView.getScene());
|
||||
}
|
||||
|
||||
public void showResultView(double score) {
|
||||
resultView.setScore(score);
|
||||
primaryStage.setScene(resultView.getScene());
|
||||
}
|
||||
|
||||
// Getter methods for views
|
||||
public LoginView getLoginView() { return loginView; }
|
||||
public RegisterView getRegisterView() { return registerView; }
|
||||
public MainMenuView getMainMenuView() { return mainMenuView; }
|
||||
public LevelSelectionView getLevelSelectionView() { return levelSelectionView; }
|
||||
public QuestionCountView getQuestionCountView() { return questionCountView; }
|
||||
public QuizView getQuizView() { return quizView; }
|
||||
public ResultView getResultView() { return resultView; }
|
||||
public void setCurrentUserName(String currentUserName){ this.currentUserName = currentUserName;}
|
||||
public String getCurrentUserName(){return this.currentUserName;}
|
||||
}
|
||||
@ -0,0 +1,21 @@
|
||||
package com.wsf.mathapp.service;
|
||||
|
||||
|
||||
import com.ybw.mathapp.service.PrimarySchoolGenerator;
|
||||
import com.ybw.mathapp.service.JuniorHighGenerator;
|
||||
import com.ybw.mathapp.service.SeniorHighGenerator;
|
||||
import com.ybw.mathapp.service.QuestionGenerator;
|
||||
|
||||
|
||||
public class QuestionService {
|
||||
|
||||
public static QuestionGenerator createGenerator(String level) {
|
||||
return switch (level) {
|
||||
case "小学" -> new PrimarySchoolGenerator();
|
||||
case "初中" -> new JuniorHighGenerator();
|
||||
case "高中" -> new SeniorHighGenerator();
|
||||
default -> null;
|
||||
};
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,190 @@
|
||||
package com.wsf.mathapp.view;
|
||||
|
||||
import com.wsf.mathapp.controller.SceneManager;
|
||||
import javafx.geometry.Insets;
|
||||
import javafx.geometry.Pos;
|
||||
import javafx.scene.Scene;
|
||||
import javafx.scene.control.Button;
|
||||
import javafx.scene.control.Label;
|
||||
import javafx.scene.layout.HBox;
|
||||
import javafx.scene.layout.Priority;
|
||||
import javafx.scene.layout.Region;
|
||||
import javafx.scene.layout.VBox;
|
||||
import javafx.scene.paint.Color;
|
||||
import javafx.scene.shape.Circle;
|
||||
import javafx.scene.text.Font;
|
||||
import javafx.scene.text.FontWeight;
|
||||
import javafx.scene.text.Text;
|
||||
|
||||
public class LevelSelectionView {
|
||||
private Scene scene;
|
||||
private final SceneManager sceneManager;
|
||||
private String currentUsername;
|
||||
|
||||
// 添加界面组件引用
|
||||
private Label usernameLabel;
|
||||
private Text avatarText;
|
||||
|
||||
public LevelSelectionView(SceneManager sceneManager) {
|
||||
this.sceneManager = sceneManager;
|
||||
this.currentUsername = sceneManager.getCurrentUserName();
|
||||
createScene();
|
||||
}
|
||||
|
||||
private void createScene() {
|
||||
// 创建主容器
|
||||
VBox mainContainer = new VBox();
|
||||
mainContainer.setPadding(new Insets(20));
|
||||
|
||||
// 创建顶部用户信息栏
|
||||
HBox userInfoBar = createUserInfoBar();
|
||||
|
||||
// 创建级别选择内容区域
|
||||
VBox selectionContent = createSelectionContent();
|
||||
|
||||
mainContainer.getChildren().addAll(userInfoBar, selectionContent);
|
||||
|
||||
scene = new Scene(mainContainer, 450, 550);
|
||||
}
|
||||
|
||||
private HBox createUserInfoBar() {
|
||||
HBox userInfoBar = new HBox(15);
|
||||
userInfoBar.setAlignment(Pos.CENTER_LEFT);
|
||||
userInfoBar.setPadding(new Insets(0, 0, 30, 0));
|
||||
userInfoBar.setStyle("-fx-border-color: #e0e0e0; -fx-border-width: 0 0 1 0; -fx-padding: 0 0 15 0;");
|
||||
|
||||
// 创建圆形头像容器
|
||||
VBox avatarContainer = new VBox();
|
||||
avatarContainer.setAlignment(Pos.CENTER);
|
||||
avatarContainer.setPrefSize(50, 50);
|
||||
|
||||
// 创建圆形头像背景
|
||||
Circle avatarCircle = new Circle(22);
|
||||
avatarCircle.setFill(Color.web("#4CAF50")); // 统一的绿色背景
|
||||
avatarCircle.setStroke(Color.WHITE);
|
||||
avatarCircle.setStrokeWidth(2);
|
||||
|
||||
// 添加阴影效果
|
||||
avatarCircle.setStyle("-fx-effect: drop shadow(gaussian, rgba(0,0,0,0.2), 5, 0.3, 2, 2);");
|
||||
|
||||
// 添加首字母文本
|
||||
avatarText = new Text(getFirstLetter());
|
||||
avatarText.setFill(Color.WHITE);
|
||||
avatarText.setFont(Font.font("Arial", FontWeight.BOLD, 16));
|
||||
|
||||
// 使用StackPane将文本放在圆形中心
|
||||
javafx.scene.layout.StackPane avatarStack = new javafx.scene.layout.StackPane();
|
||||
avatarStack.getChildren().addAll(avatarCircle, avatarText);
|
||||
avatarStack.setPrefSize(44, 44);
|
||||
avatarStack.setAlignment(Pos.CENTER);
|
||||
|
||||
avatarContainer.getChildren().add(avatarStack);
|
||||
|
||||
// 用户名标签
|
||||
usernameLabel = new Label(currentUsername != null ? currentUsername : "用户");
|
||||
usernameLabel.setFont(Font.font("Arial", FontWeight.BOLD, 16));
|
||||
usernameLabel.setStyle("-fx-text-fill: #2c3e50;");
|
||||
|
||||
// 间隔
|
||||
Region spacer = new Region();
|
||||
HBox.setHgrow(spacer, Priority.ALWAYS);
|
||||
|
||||
userInfoBar.getChildren().addAll(avatarContainer, usernameLabel, spacer);
|
||||
|
||||
return userInfoBar;
|
||||
}
|
||||
|
||||
private VBox createSelectionContent() {
|
||||
VBox selectionContent = new VBox(25);
|
||||
selectionContent.setPadding(new Insets(30, 20, 20, 20));
|
||||
selectionContent.setAlignment(Pos.CENTER);
|
||||
|
||||
Label titleLabel = new Label("选择题目级别");
|
||||
titleLabel.setFont(Font.font("Arial", FontWeight.BOLD, 26));
|
||||
titleLabel.setStyle("-fx-text-fill: #2c3e50;");
|
||||
|
||||
// 添加副标题
|
||||
Label subtitleLabel = new Label("请选择适合您的学习级别");
|
||||
subtitleLabel.setFont(Font.font("Arial", 14));
|
||||
subtitleLabel.setStyle("-fx-text-fill: #7f8c8d; -fx-padding: 0 0 10 0;");
|
||||
|
||||
Button primaryButton = createLevelButton("小学题目", "#4CAF50", "#45a049");
|
||||
Button juniorButton = createLevelButton("初中题目", "#2196F3", "#1976D2");
|
||||
Button seniorButton = createLevelButton("高中题目", "#9C27B0", "#7B1FA2");
|
||||
|
||||
Button backButton = new Button("返回主菜单");
|
||||
backButton.setStyle("-fx-background-color: #95a5a6; -fx-text-fill: white; -fx-font-size: 14px; -fx-background-radius: 8; -fx-padding: 8 20;");
|
||||
backButton.setPrefSize(180, 45);
|
||||
backButton.setOnMouseEntered(e -> backButton.setStyle("-fx-background-color: #7f8c8d; -fx-text-fill: white; -fx-font-size: 14px; -fx-background-radius: 8; -fx-padding: 8 20;"));
|
||||
backButton.setOnMouseExited(e -> backButton.setStyle("-fx-background-color: #95a5a6; -fx-text-fill: white; -fx-font-size: 14px; -fx-background-radius: 8; -fx-padding: 8 20;"));
|
||||
|
||||
primaryButton.setOnAction(e -> {
|
||||
String selectedLevel = "小学";
|
||||
sceneManager.getQuestionCountView().setLevel(selectedLevel);
|
||||
sceneManager.showQuestionCountView();
|
||||
});
|
||||
|
||||
juniorButton.setOnAction(e -> {
|
||||
String selectedLevel = "初中";
|
||||
sceneManager.getQuestionCountView().setLevel(selectedLevel);
|
||||
sceneManager.showQuestionCountView();
|
||||
});
|
||||
|
||||
seniorButton.setOnAction(e -> {
|
||||
String selectedLevel = "高中";
|
||||
sceneManager.getQuestionCountView().setLevel(selectedLevel);
|
||||
sceneManager.showQuestionCountView();
|
||||
});
|
||||
|
||||
backButton.setOnAction(e -> {
|
||||
sceneManager.showMainMenuView();
|
||||
});
|
||||
|
||||
selectionContent.getChildren().addAll(
|
||||
titleLabel, subtitleLabel, primaryButton, juniorButton, seniorButton, backButton
|
||||
);
|
||||
|
||||
return selectionContent;
|
||||
}
|
||||
|
||||
private Button createLevelButton(String text, String color, String hoverColor) {
|
||||
Button button = new Button(text);
|
||||
button.setStyle(String.format(
|
||||
"-fx-background-color: %s; -fx-text-fill: white; -fx-font-size: 16px; -fx-font-weight: bold; " +
|
||||
"-fx-background-radius: 12; -fx-padding: 12 30; -fx-effect: drop shadow(gaussian, rgba(0,0,0,0.2), 8, 0.3, 2, 2);",
|
||||
color
|
||||
));
|
||||
button.setPrefSize(220, 60);
|
||||
button.setOnMouseEntered(e -> button.setStyle(String.format(
|
||||
"-fx-background-color: %s; -fx-text-fill: white; -fx-font-size: 16px; -fx-font-weight: bold; " +
|
||||
"-fx-background-radius: 12; -fx-padding: 12 30; -fx-effect: drop shadow(gaussian, rgba(0,0,0,0.3), 10, 0.4, 3, 3);",
|
||||
hoverColor
|
||||
)));
|
||||
button.setOnMouseExited(e -> button.setStyle(String.format(
|
||||
"-fx-background-color: %s; -fx-text-fill: white; -fx-font-size: 16px; -fx-font-weight: bold; " +
|
||||
"-fx-background-radius: 12; -fx-padding: 12 30; -fx-effect: drop shadow(gaussian, rgba(0,0,0,0.2), 8, 0.3, 2, 2);",
|
||||
color
|
||||
)));
|
||||
return button;
|
||||
}
|
||||
|
||||
private String getFirstLetter() {
|
||||
return currentUsername != null && !currentUsername.isEmpty() ?
|
||||
currentUsername.substring(0, 1).toUpperCase() : "U";
|
||||
}
|
||||
|
||||
// 添加更新用户名的方法
|
||||
public void updateUsername(String username) {
|
||||
this.currentUsername = username;
|
||||
if (usernameLabel != null) {
|
||||
usernameLabel.setText(username != null ? username : "用户");
|
||||
}
|
||||
if (avatarText != null) {
|
||||
avatarText.setText(getFirstLetter());
|
||||
}
|
||||
}
|
||||
|
||||
public Scene getScene() {
|
||||
return scene;
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,113 @@
|
||||
package com.wsf.mathapp.view;
|
||||
|
||||
import com.wsf.mathapp.controller.SceneManager;
|
||||
import com.ybw.mathapp.util.Login;
|
||||
import com.ybw.mathapp.util.LoginFileUtils;
|
||||
import com.ybw.mathapp.util.Register;
|
||||
import javafx.geometry.Insets;
|
||||
import javafx.geometry.Pos;
|
||||
import javafx.scene.Scene;
|
||||
import javafx.scene.control.*;
|
||||
import javafx.scene.layout.VBox;
|
||||
import javafx.scene.text.Font;
|
||||
|
||||
public class LoginView {
|
||||
private Scene scene;
|
||||
private final SceneManager sceneManager;
|
||||
|
||||
public LoginView(SceneManager sceneManager) {
|
||||
this.sceneManager = sceneManager;
|
||||
createScene();
|
||||
}
|
||||
|
||||
private void createScene() {
|
||||
VBox root = new VBox(20);
|
||||
root.setPadding(new Insets(40));
|
||||
root.setAlignment(Pos.CENTER);
|
||||
|
||||
Label titleLabel = new Label("数学学习软件");
|
||||
titleLabel.setFont(Font.font(24));
|
||||
|
||||
Label subtitleLabel = new Label("用户登录");
|
||||
subtitleLabel.setFont(Font.font(18));
|
||||
|
||||
// 修改提示文本
|
||||
TextField usernameOrEmailField = new TextField();
|
||||
usernameOrEmailField.setPromptText("请输入用户名或邮箱");
|
||||
usernameOrEmailField.setMaxWidth(300);
|
||||
usernameOrEmailField.setPrefHeight(40);
|
||||
|
||||
PasswordField passwordField = new PasswordField();
|
||||
passwordField.setPromptText("请输入密码");
|
||||
passwordField.setMaxWidth(300);
|
||||
passwordField.setPrefHeight(40);
|
||||
|
||||
Button loginButton = new Button("登录");
|
||||
loginButton.setStyle("-fx-background-color: #4CAF50; -fx-text-fill: white; -fx-font-size: 14px;");
|
||||
loginButton.setPrefSize(300, 40);
|
||||
|
||||
Button registerButton = new Button("注册账号");
|
||||
registerButton.setStyle("-fx-background-color: #2196F3; -fx-text-fill: white; -fx-font-size: 14px;");
|
||||
registerButton.setPrefSize(300, 40);
|
||||
|
||||
Label statusLabel = new Label();
|
||||
|
||||
loginButton.setOnAction(e -> {
|
||||
String usernameOrEmail = usernameOrEmailField.getText().trim();
|
||||
String password = passwordField.getText();
|
||||
|
||||
if (usernameOrEmail.isEmpty() || password.isEmpty()) {
|
||||
showError(statusLabel, "用户名/邮箱和密码不能为空!");
|
||||
return;
|
||||
}
|
||||
|
||||
// 调用后端的登录方法,支持用户名或邮箱登录
|
||||
boolean success = Login.login(usernameOrEmail, password);
|
||||
System.out.println(usernameOrEmail);
|
||||
System.out.println(password);
|
||||
if (success) {
|
||||
showSuccess(statusLabel);
|
||||
String username;
|
||||
if (LoginFileUtils.emailFindName(usernameOrEmail) == null){
|
||||
username = usernameOrEmail;
|
||||
}
|
||||
else {
|
||||
username = LoginFileUtils.emailFindName(usernameOrEmail);
|
||||
}
|
||||
sceneManager.setCurrentUserName(username);
|
||||
sceneManager.showMainMenuView();
|
||||
} else {
|
||||
showError(statusLabel, "用户名/邮箱或密码错误!");
|
||||
}
|
||||
});
|
||||
|
||||
registerButton.setOnAction(e -> {
|
||||
sceneManager.showRegisterView();
|
||||
});
|
||||
|
||||
// 添加回车键登录支持
|
||||
usernameOrEmailField.setOnAction(e -> loginButton.fire());
|
||||
passwordField.setOnAction(e -> loginButton.fire());
|
||||
|
||||
root.getChildren().addAll(
|
||||
titleLabel, subtitleLabel, usernameOrEmailField, passwordField,
|
||||
loginButton, registerButton, statusLabel
|
||||
);
|
||||
|
||||
scene = new Scene(root, 400, 500);
|
||||
}
|
||||
|
||||
private void showError(Label label, String message) {
|
||||
label.setText(message);
|
||||
label.setStyle("-fx-text-fill: red;");
|
||||
}
|
||||
|
||||
private void showSuccess(Label label) {
|
||||
label.setText("登录成功!");
|
||||
label.setStyle("-fx-text-fill: green;");
|
||||
}
|
||||
|
||||
public Scene getScene() {
|
||||
return scene;
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,152 @@
|
||||
package com.wsf.mathapp.view;
|
||||
|
||||
import com.wsf.mathapp.controller.SceneManager;
|
||||
import com.wsf.mathapp.service.QuestionService;
|
||||
import com.ybw.mathapp.entity.QuestionWithOptions;
|
||||
import com.ybw.mathapp.service.MultipleChoiceGenerator;
|
||||
import com.ybw.mathapp.service.QuestionGenerator;
|
||||
import javafx.geometry.Insets;
|
||||
import javafx.geometry.Pos;
|
||||
import javafx.scene.Scene;
|
||||
import javafx.scene.control.*;
|
||||
import javafx.scene.layout.VBox;
|
||||
import javafx.scene.text.Font;
|
||||
import java.util.List;
|
||||
|
||||
public class QuizView {
|
||||
private Scene scene;
|
||||
private final SceneManager sceneManager;
|
||||
private MultipleChoiceGenerator multipleChoiceGenerator = null;
|
||||
private String currentLevel;
|
||||
private int questionCount;
|
||||
private List<QuestionWithOptions> questions;
|
||||
private int correctAnswers = 0;
|
||||
|
||||
private Label questionLabel;
|
||||
private ToggleGroup optionsGroup;
|
||||
private VBox optionsContainer;
|
||||
private Button nextButton;
|
||||
private Label progressLabel;
|
||||
private Label questionNumberLabel;
|
||||
|
||||
public QuizView(SceneManager sceneManager) {
|
||||
this.sceneManager = sceneManager;
|
||||
createScene();
|
||||
}
|
||||
|
||||
private void createScene() {
|
||||
VBox root = new VBox(20);
|
||||
root.setPadding(new Insets(30));
|
||||
root.setAlignment(Pos.TOP_CENTER);
|
||||
|
||||
progressLabel = new Label();
|
||||
progressLabel.setFont(Font.font(14));
|
||||
|
||||
questionNumberLabel = new Label();
|
||||
questionNumberLabel.setFont(Font.font(16));
|
||||
questionNumberLabel.setStyle("-fx-text-fill: #666;");
|
||||
|
||||
questionLabel = new Label();
|
||||
questionLabel.setFont(Font.font(18));
|
||||
questionLabel.setWrapText(true);
|
||||
questionLabel.setStyle("-fx-padding: 10 0 20 0;");
|
||||
|
||||
optionsGroup = new ToggleGroup();
|
||||
optionsContainer = new VBox(15);
|
||||
optionsContainer.setAlignment(Pos.CENTER_LEFT);
|
||||
optionsContainer.setPadding(new Insets(10));
|
||||
|
||||
nextButton = new Button("下一题");
|
||||
nextButton.setStyle("-fx-background-color: #4CAF50; -fx-text-fill: white; -fx-font-size: 14px;");
|
||||
nextButton.setPrefSize(150, 40);
|
||||
nextButton.setDisable(true);
|
||||
|
||||
root.getChildren().addAll(progressLabel, questionNumberLabel, questionLabel, optionsContainer, nextButton);
|
||||
|
||||
scene = new Scene(root, 600, 500);
|
||||
}
|
||||
|
||||
public void setQuizParameters(String level, int count) {
|
||||
this.currentLevel = level;
|
||||
this.questionCount = count;
|
||||
this.correctAnswers = 0;
|
||||
|
||||
// 生成题目
|
||||
generateQuestions();
|
||||
showQuestion(0);
|
||||
}
|
||||
|
||||
private void generateQuestions() {
|
||||
QuestionGenerator questionGenerator = QuestionService.createGenerator(currentLevel);
|
||||
multipleChoiceGenerator = new MultipleChoiceGenerator(questionGenerator,currentLevel);
|
||||
questions = multipleChoiceGenerator.generateMultipleChoiceQuestions(questionCount);
|
||||
}
|
||||
|
||||
private void showQuestion(int index) {
|
||||
if (index >= questions.size()) {
|
||||
// 所有题目已回答,显示结果
|
||||
double score = (double) correctAnswers / questions.size();
|
||||
sceneManager.showResultView(score);
|
||||
return;
|
||||
}
|
||||
QuestionWithOptions question = questions.get(index);
|
||||
|
||||
// 更新进度和题号
|
||||
progressLabel.setText("进度: " + (index + 1) + "/" + questions.size());
|
||||
questionNumberLabel.setText("第 " + (index + 1) + " 题");
|
||||
|
||||
// 设置题目内容
|
||||
String questionText = question.getQuestionText();
|
||||
// 移除末尾的 "="
|
||||
if (questionText.endsWith(" =")) {
|
||||
questionText = questionText.substring(0, questionText.length() - 2);
|
||||
}
|
||||
questionLabel.setText(questionText + " = ?");
|
||||
|
||||
// 清空选项容器
|
||||
optionsContainer.getChildren().clear();
|
||||
optionsGroup = new ToggleGroup();
|
||||
|
||||
// 添加选项
|
||||
List<String> options = question.getOptions();
|
||||
for (int i = 0; i < options.size(); i++) {
|
||||
RadioButton radioButton = new RadioButton((char)('A' + i) + ". " + options.get(i));
|
||||
radioButton.setToggleGroup(optionsGroup);
|
||||
radioButton.setFont(Font.font(14));
|
||||
radioButton.setWrapText(true);
|
||||
radioButton.setPrefWidth(500);
|
||||
optionsContainer.getChildren().add(radioButton);
|
||||
}
|
||||
|
||||
// 设置下一题按钮
|
||||
nextButton.setDisable(true);
|
||||
nextButton.setText(index == questions.size() - 1 ? "提交答案" : "下一题");
|
||||
nextButton.setOnAction(e -> {
|
||||
checkAnswer(question);
|
||||
showQuestion(index + 1);
|
||||
});
|
||||
|
||||
// 启用下一题按钮当选择了一个选项时
|
||||
optionsGroup.selectedToggleProperty().addListener((obs, oldVal, newVal) -> {
|
||||
nextButton.setDisable(newVal == null);
|
||||
});
|
||||
}
|
||||
|
||||
private void checkAnswer(QuestionWithOptions question) {
|
||||
RadioButton selectedRadioButton = (RadioButton) optionsGroup.getSelectedToggle();
|
||||
if (selectedRadioButton != null) {
|
||||
int selectedIndex = optionsContainer.getChildren().indexOf(selectedRadioButton);
|
||||
if (selectedIndex == question.getCorrectAnswerIndex()) {
|
||||
correctAnswers++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public Scene getScene() {
|
||||
return scene;
|
||||
}
|
||||
|
||||
public MultipleChoiceGenerator getMultipleChoiceGenerator() {
|
||||
return multipleChoiceGenerator;
|
||||
}
|
||||
}
|
||||
@ -1,24 +0,0 @@
|
||||
package com.ybw.mathapp;
|
||||
|
||||
import javafx.application.Application;
|
||||
import javafx.fxml.FXMLLoader;
|
||||
import javafx.scene.Scene;
|
||||
import javafx.stage.Stage;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
public class HelloApplication extends Application {
|
||||
|
||||
@Override
|
||||
public void start(Stage stage) throws IOException {
|
||||
FXMLLoader fxmlLoader = new FXMLLoader(HelloApplication.class.getResource("hello-view.fxml"));
|
||||
Scene scene = new Scene(fxmlLoader.load(), 320, 240);
|
||||
stage.setTitle("Hello!");
|
||||
stage.setScene(scene);
|
||||
stage.show();
|
||||
}
|
||||
|
||||
public static void main(String[] args) {
|
||||
launch();
|
||||
}
|
||||
}
|
||||
@ -1,15 +0,0 @@
|
||||
package com.ybw.mathapp;
|
||||
|
||||
import javafx.fxml.FXML;
|
||||
import javafx.scene.control.Label;
|
||||
|
||||
public class HelloController {
|
||||
|
||||
@FXML
|
||||
private Label welcomeText;
|
||||
|
||||
@FXML
|
||||
protected void onHelloButtonClick() {
|
||||
welcomeText.setText("Welcome to JavaFX Application!");
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,36 @@
|
||||
package com.ybw.mathapp;
|
||||
|
||||
import com.ybw.mathapp.entity.QuestionWithOptions;
|
||||
import com.ybw.mathapp.service.JuniorHighGenerator;
|
||||
import com.ybw.mathapp.service.MultipleChoiceGenerator;
|
||||
import com.ybw.mathapp.service.PrimarySchoolGenerator;
|
||||
import java.util.List;
|
||||
|
||||
public class Main {
|
||||
public static void main(String[] args) {
|
||||
// 生成小学选择题
|
||||
System.out.println("--- Primary School MCQs ---");
|
||||
PrimarySchoolGenerator primaryGen = new PrimarySchoolGenerator();
|
||||
MultipleChoiceGenerator primaryMC = new MultipleChoiceGenerator(primaryGen, "小学"); // 传入级别
|
||||
List<QuestionWithOptions> primaryMCQs = primaryMC.generateMultipleChoiceQuestions(10);
|
||||
primaryMCQs.forEach(q -> System.out.println(q + "\n"));
|
||||
|
||||
// 生成初中选择题
|
||||
System.out.println("--- Junior High MCQs ---");
|
||||
JuniorHighGenerator juniorGen = new JuniorHighGenerator();
|
||||
MultipleChoiceGenerator juniorMC = new MultipleChoiceGenerator(juniorGen, "初中"); // 传入级别
|
||||
List<QuestionWithOptions> juniorMCQs = juniorMC.generateMultipleChoiceQuestions(10);
|
||||
juniorMCQs.forEach(q -> System.out.println(q + "\n"));
|
||||
|
||||
System.out.println();
|
||||
/*
|
||||
// 生成高中选择题
|
||||
System.out.println("--- Senior High MCQs ---");
|
||||
SeniorHighGenerator seniorGen = new SeniorHighGenerator();
|
||||
MultipleChoiceGenerator seniorMC = new MultipleChoiceGenerator(seniorGen, "高中"); // 传入级别
|
||||
List<QuestionWithOptions> seniorMCQs = seniorMC.generateMultipleChoiceQuestions(2, 4);
|
||||
seniorMCQs.forEach(q -> System.out.println(q + "\n"));
|
||||
*/
|
||||
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,91 @@
|
||||
package com.ybw.mathapp.util;
|
||||
|
||||
import static com.ybw.mathapp.util.LoginFileUtils.USER_FILE;
|
||||
|
||||
import java.io.BufferedReader;
|
||||
import java.io.BufferedWriter;
|
||||
import java.io.File;
|
||||
import java.io.FileReader;
|
||||
import java.io.FileWriter;
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
public class ChangePassword {
|
||||
static final List<String> lines = new ArrayList<>();
|
||||
static String userLine = null;
|
||||
static int userLineNumber = -1;
|
||||
|
||||
// 前端接口-修改密码
|
||||
public static boolean changePassword(String name, String newPassword) {
|
||||
File file = new File(USER_FILE);
|
||||
if (!file.exists()) {
|
||||
System.out.println("用户文件不存在: " + USER_FILE);
|
||||
return false;
|
||||
}
|
||||
|
||||
// 1. 读取文件,查找用户
|
||||
if(!findUserLine(name, file)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (userLine == null || userLineNumber == -1) {
|
||||
// 用户未找到
|
||||
System.out.println("用户 '" + name + "' 不存在,修改失败。");
|
||||
return false;
|
||||
}
|
||||
|
||||
// 2. 更新找到的用户行中的密码
|
||||
String[] parts = userLine.split(",");
|
||||
if (parts.length != 3) {
|
||||
return false;
|
||||
}
|
||||
parts[2] = newPassword; // 假设密码是第三个字段
|
||||
String updatedLine = String.join(",", parts);
|
||||
|
||||
lines.set(userLineNumber, updatedLine); // 替换列表中的旧行
|
||||
|
||||
// 3. 将更新后的内容写回文件
|
||||
if(!writeBack(lines, file)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public static boolean writeBack(List<String> lines, File file) {
|
||||
try (BufferedWriter writer = new BufferedWriter(new FileWriter(file))) {
|
||||
for (String l : lines) {
|
||||
writer.write(l);
|
||||
writer.newLine();
|
||||
}
|
||||
} catch (IOException e) {
|
||||
System.err.println("写入文件时出错: " + e.getMessage());
|
||||
return false; // 如果写回失败,认为修改未成功
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
public static boolean findUserLine(String name, File file) {
|
||||
try (BufferedReader reader = new BufferedReader(new FileReader(file))) {
|
||||
String line;
|
||||
int currentLineNum = 0;
|
||||
while ((line = reader.readLine()) != null) {
|
||||
lines.add(line);
|
||||
String[] parts = line.split(",");
|
||||
// 假设格式为: username,email,password
|
||||
if (parts.length >= 3 && parts[0].equals(name)) {
|
||||
userLine = line; // 找到用户行
|
||||
userLineNumber = currentLineNum;
|
||||
break; // 找到后可以退出循环
|
||||
}
|
||||
currentLineNum++;
|
||||
}
|
||||
} catch (IOException e) {
|
||||
System.err.println("读取文件时出错: " + e.getMessage());
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,16 @@
|
||||
package com.ybw.mathapp.util;
|
||||
|
||||
public class Login {
|
||||
|
||||
// 前端接口-登录成功or失败
|
||||
public static boolean login(String name, String password) {
|
||||
if (LoginFileUtils.validateUser(name, password)) {
|
||||
System.out.println("登录成功!欢迎回来," + name);
|
||||
return true;
|
||||
} else {
|
||||
System.out.println("邮箱或密码错误!");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,95 @@
|
||||
package com.ybw.mathapp.util;
|
||||
|
||||
import com.ybw.mathapp.entity.User;
|
||||
import java.io.*;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
public class LoginFileUtils {
|
||||
static final String USER_FILE = "users.txt";
|
||||
|
||||
// 读取所有用户
|
||||
public static List<User> readUsers() {
|
||||
List<User> users = new ArrayList<>();
|
||||
File file = new File(USER_FILE);
|
||||
|
||||
if (!file.exists()) {
|
||||
try {
|
||||
file.createNewFile();
|
||||
} catch (IOException e) {
|
||||
System.err.println("创建用户文件失败: " + e.getMessage());
|
||||
}
|
||||
return users;
|
||||
}
|
||||
|
||||
try (BufferedReader reader = new BufferedReader(new FileReader(file))) {
|
||||
String line;
|
||||
while ((line = reader.readLine()) != null) {
|
||||
line = line.trim();
|
||||
if (line.isEmpty()) continue;
|
||||
|
||||
User user = User.fromString(line);
|
||||
if (user != null) {
|
||||
users.add(user);
|
||||
}
|
||||
}
|
||||
} catch (IOException e) {
|
||||
System.err.println("读取用户文件失败: " + e.getMessage());
|
||||
}
|
||||
return users;
|
||||
}
|
||||
|
||||
// 保存用户到文件
|
||||
public static void saveUser(User user) {
|
||||
try (PrintWriter writer = new PrintWriter(new FileWriter(USER_FILE, true))) {
|
||||
writer.println(user.toString());
|
||||
} catch (IOException e) {
|
||||
System.err.println("保存用户信息失败: " + e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
// 前端接口-检查邮箱是否已注册
|
||||
public static boolean isEmailRegistered(String email) {
|
||||
List<User> users = readUsers();
|
||||
for (User user : users) {
|
||||
if (user.getEmail().equalsIgnoreCase(email)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// 前端接口-检查用户名是否已注册
|
||||
public static boolean isNameRegistered(String name) {
|
||||
List<User> users = readUsers();
|
||||
for (User user : users) {
|
||||
if (user.getName().equalsIgnoreCase(name)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// 前端接口-验证用户登录
|
||||
public static boolean validateUser(String emailOrName, String password) {
|
||||
List<User> users = readUsers();
|
||||
for (User user : users) {
|
||||
if ((user.getEmail().equalsIgnoreCase(emailOrName)
|
||||
|| user.getName().equalsIgnoreCase(emailOrName) )
|
||||
&& user.getPassword().equals(password)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
// 前端接口-通过邮箱查找用户名
|
||||
public static String emailFindName (String email) {
|
||||
List<User> users = readUsers();
|
||||
for (User user : users) {
|
||||
if (user.getEmail().equalsIgnoreCase(email)) {
|
||||
return user.getName();
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@ -1,16 +1,10 @@
|
||||
module com.ybw.mathapp {
|
||||
requires javafx.controls;
|
||||
requires javafx.fxml;
|
||||
requires javafx.web;
|
||||
requires javafx.base;
|
||||
requires javafx.graphics;
|
||||
requires jakarta.mail;
|
||||
|
||||
requires org.controlsfx.controls;
|
||||
requires com.dlsc.formsfx;
|
||||
requires net.synedra.validatorfx;
|
||||
requires org.kordamp.ikonli.javafx;
|
||||
requires org.kordamp.bootstrapfx.core;
|
||||
requires eu.hansolo.tilesfx;
|
||||
requires com.almasb.fxgl.all;
|
||||
|
||||
opens com.ybw.mathapp to javafx.fxml;
|
||||
exports com.ybw.mathapp;
|
||||
opens com.wsf.mathapp to javafx.fxml;
|
||||
exports com.wsf.mathapp;
|
||||
}
|
||||
@ -0,0 +1,2 @@
|
||||
rfc822=smtp
|
||||
smtp=smtp
|
||||
@ -1,16 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
|
||||
<?import javafx.geometry.Insets?>
|
||||
<?import javafx.scene.control.Label?>
|
||||
<?import javafx.scene.layout.VBox?>
|
||||
|
||||
<?import javafx.scene.control.Button?>
|
||||
<VBox alignment="CENTER" spacing="20.0" xmlns:fx="http://javafx.com/fxml"
|
||||
fx:controller="com.ybw.mathapp.HelloController">
|
||||
<padding>
|
||||
<Insets bottom="20.0" left="20.0" right="20.0" top="20.0"/>
|
||||
</padding>
|
||||
|
||||
<Label fx:id="welcomeText"/>
|
||||
<Button text="Hello!" onAction="#onHelloButtonClick"/>
|
||||
</VBox>
|
||||
Loading…
Reference in new issue