鱼C论坛

 找回密码
 立即注册
楼主: zqy173590939

[学习笔记] Java实验完成

[复制链接]
发表于 2023-12-31 22:01:43 | 显示全部楼层
zqy173590939 发表于 2023-12-31 22:00
@FishC
package com.example.javafxmw;

import ga ...


这段代码主要是一个界面交互程序,使用JavaFX创建了一个口算习题薄的应用。下面我将分析一下代码的主要逻辑。

首先,在start方法中设置了一个菜单栏,其中包括了Generate、Save、Read、Check、Delete、Redo Mistakes Equations等功能选项。并将这些菜单选项与相应的事件处理器关联起来。

在generateMenuItem选项的事件处理器中,调用了generateEquation方法生成算式,并将生成的算式添加到flowPane中,并且将算式保存到数据库中。

在saveMenuItem选项的事件处理器中,遍历flowPane中的每一个算式,将算式的相关信息(如ID、算式、用户答案)保存到数据库中。

在readMenuItem选项的事件处理器中,从数据库中读取所有的算式,并显示在flowPane中。

在checkMenuItem选项的事件处理器中,统计用户答对题目和答错题目的数量,计算正确率和错误率,并显示在界面上。

在viewAccuracyButton的点击事件监听器中,显示饼状图,展示正确率和错误率。

在deleteMenuItem和deleteMenuItem1选项的事件处理器中,实现了删除算术式的功能。deleteMenuItem可以删除指定范围内的算术式,deleteMenuItem1可以删除所有的算术式。

在mistakesEquationsCollection选项的事件处理器中,可以重新做错误的习题。

总结一下,这段代码通过JavaFX实现了一个口算习题薄的应用,可以生成算式、保存算式、读取算式、检查习题、删除算术式等功能,并提供了可视化的界面和统计信息展示。

以上回复来自 FishC AI 小助理,如未能正确解答您的问题,请继续追问。
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

 楼主| 发表于 2023-12-31 22:20:16 | 显示全部楼层
package com.example.javafxmw;

import gaijin3.*;
import javafx.application.Application;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.geometry.Insets;
import javafx.scene.Node;
import javafx.scene.Scene;
import javafx.scene.chart.PieChart;
import javafx.scene.control.*;
import javafx.scene.image.Image;
import javafx.scene.layout.BorderPane;
import javafx.scene.layout.FlowPane;
import javafx.scene.layout.GridPane;
import javafx.scene.layout.HBox;
import javafx.stage.Stage;
import javafx.util.Pair;

import java.io.IOException;
import java.sql.*;
import java.util.Optional;

public class HelloApplication extends Application
{
    // 定义全局变量
    //定义一个TextArea控件作为全局变量
    TextArea infoTextArea = new TextArea();

    Button viewAccuracyButton = new Button("View Accuracy");

    FlowPane flowPane = new FlowPane();
    ScrollPane scrollPane = new ScrollPane();// 创建一个滚动面板对象
    private int maxID = 0;

    @Override
    public void start(Stage stage) throws IOException {
        MenuItem generateMenuItem = new MenuItem("Generate");

        // 事件处理器代码
        generateMenuItem.setOnAction(new EventHandler<ActionEvent>() {
            @Override
            public void handle(ActionEvent event) {
                generateEquation();
            }
        });

        MenuItem saveMenuItem = new MenuItem("Save");

        saveMenuItem.setOnAction(new EventHandler<ActionEvent>() {
            @Override
            public void handle(ActionEvent event) {
                saveEquations();
                connectDatabase();
            }
        });

        MenuItem readMenuItem = new MenuItem("Read");

        readMenuItem.setOnAction(new EventHandler<ActionEvent>() {
            @Override
            public void handle(ActionEvent event) {
                flowPane.getChildren().clear(); // 清空当前GUI界面
                showAlert("习题已读取");
                displayAllEquationsFromDatabase();
            }
        });

        MenuItem checkMenuItem = new MenuItem("Check");

        checkMenuItem.setOnAction(new EventHandler<ActionEvent>() {
            @Override
            public void handle(ActionEvent event) {
                // 检查习题
                checkEquations();
            }
        });

        // View Accuracy按钮的点击事件监听器
        viewAccuracyButton.setOnAction(new EventHandler<ActionEvent>() {
            @Override
            public void handle(ActionEvent event) {
                // 显示饼状图
                showAccuracyChart();
            }
        });

        MenuItem deleteMenuItem = new MenuItem("Delete by serial number");

        // Delete by serial number按钮的点击事件监听器,部分删除算数式
        deleteMenuItem.setOnAction(new EventHandler<ActionEvent>() {
            @Override
            public void handle(ActionEvent event) {
                deleteEquations();
            }
        });

        MenuItem deleteMenuItem1 = new MenuItem("Delete all");

        // Delete all按钮的点击事件监听器,全部删除
        deleteMenuItem1.setOnAction(new EventHandler<ActionEvent>() {
            @Override
            public void handle(ActionEvent event) {
                // 删除数据库中的所有算术式
                deleteAllEquations();

                // 清空界面上的所有算术式
                flowPane.getChildren().clear();

                showAlert("所有算术式删除成功!");
            }
        });

        MenuItem mistakesEquationsCollection = new MenuItem("Redo Mistakes Equations");

        Menu fileMenu = new Menu("File");
        Menu saveMenu = new Menu("SaveEquation");
        Menu readMenu = new Menu("ReadEquation");
        Menu checkMenu = new Menu("CheckEquation");
        Menu deleteMenu = new Menu("Delete");
        Menu mistakesEquationsCollectionMenu = new Menu("MistakesEquationsCollection");

        fileMenu.getItems().addAll(generateMenuItem);
        saveMenu.getItems().add(saveMenuItem);
        readMenu.getItems().add(readMenuItem);
        checkMenu.getItems().add(checkMenuItem);
        deleteMenu.getItems().addAll(deleteMenuItem,deleteMenuItem1);
        mistakesEquationsCollectionMenu.getItems().add(mistakesEquationsCollection);

        MenuBar menuBar = new MenuBar();
        menuBar.getMenus().addAll(fileMenu);
        menuBar.getMenus().add(saveMenu);
        menuBar.getMenus().add(readMenu);
        menuBar.getMenus().add(checkMenu);
        menuBar.getMenus().add(deleteMenu);
        menuBar.getMenus().add(mistakesEquationsCollectionMenu);

        flowPane.setHgap(50);
        flowPane.setVgap(30);
        flowPane.setPadding(new Insets(20));
        flowPane.setPrefSize(800, 560); // 设置 FlowPane 的大小

        BorderPane borderPane = new BorderPane();
        borderPane.setTop(menuBar);
        borderPane.setCenter(flowPane);

        //为了解决题目生成或多flowpane没有拖动条无法显示的问题
        // 将FlowPane放在一个ScrollPane中
        scrollPane.setContent(flowPane);// 设置滚动面板的内容为 flowPane,即将 flowPane 放入滚动面板中
        scrollPane.setFitToHeight(true);// 可以让滚动面板的高度自适应内容的高度
        borderPane.setCenter(scrollPane); // 将ScrollPane放置在中心位置

        HBox bottomBox = new HBox(10, viewAccuracyButton);
        HBox.setMargin(viewAccuracyButton, new Insets(50, 0, 20, 140));
        borderPane.setBottom(bottomBox);

        Scene scene = new Scene(borderPane, 800, 640);
        stage.setTitle("口算习题薄");
        stage.setScene(scene);
        stage.show();

        infoTextArea.setPrefSize(400, 110);
        //将TextArea控件其设置为只读
        infoTextArea.setEditable(false);

        HBox showbottomBox = new HBox(140, viewAccuracyButton, infoTextArea);
        HBox.setMargin(infoTextArea, new Insets(20, 0, 20, 0));
        borderPane.setBottom(showbottomBox);


    }


    public static void main(String[] args) {
        launch();
    }

    //为了使generate的事件处理器更美观特意拉出了这个类
    public EquationCollection generateEquation() {
        // 创建一个警示对话框
        TextInputDialog dialog = new TextInputDialog("5");
        dialog.setTitle("请输入算式数量");
        dialog.setHeaderText(null);
        dialog.setContentText("算式数量:");

        // 显示对话框,并获取用户输入的算式数量
        Optional<String> result = dialog.showAndWait();
        if (result.isPresent())
        {
            int n = Integer.parseInt(result.get());

            // 生成算式
            EquationCollection equationCollection = generateEquations(n);

            // 清空之前的内容
            flowPane.getChildren().clear();

            // 遍历算式集合并显示在GUI中
            for (IEquation equation : equationCollection)
            {
                maxID++; // id自增
                Label idLabel = new Label(String.valueOf(maxID)); // 获取当前最大ID,并将新的算式ID设为其加1
                Label equationLabel = new Label(equation.toString());
                TextField answerField = new TextField(); // 创建一个新的文本框
                HBox equationBox = new HBox(10, idLabel, new Label("、"), equationLabel, answerField); // 将算式ID标签、顿号、算式标签和文本框放入水平布局
                flowPane.getChildren().add(equationBox); // 将水平布局添加到 flowPane 中
            }

            // 连接数据库
            connectDatabase();
        }
        return null;
    }

    // 生成算式的方法
    public EquationCollection generateEquations(int n) {
        EquationCollection equationCollection = new EquationCollection();
        EquationCheckerOfRange equationChecker = new EquationCheckerOfRange(0, 100);
        equationCollection.generate(n, equationChecker);
        return equationCollection;
    }

    // 连接数据库的方法
    public void connectDatabase() {
        Connection conn = null;
        Statement stmt = null;
        try {
            Class.forName("com.mysql.cj.jdbc.Driver");
            conn = DriverManager.getConnection(
                    "jdbc:mysql://localhost:3306/rjgzdatabase?characterEncoding=utf8&serverTimezone=Asia/Shanghai&useSSL=false",
                    "root", "Zqy173590939");

            DatabaseMetaData dbMeta = conn.getMetaData();
            System.out.println("当前用户:" + dbMeta.getUserName());
            System.out.println("驱动版本:" + dbMeta.getDriverVersion());
            System.out.println("MySQL版本:" + dbMeta.getDatabaseProductVersion());

            stmt = conn.createStatement();

            // 查询最大ID值
            ResultSet rs = stmt.executeQuery("SELECT MAX(id) FROM equationtable");
            if (rs.next()) {
                maxID = rs.getInt(1);
            }

        } catch (SQLException se) {
            se.printStackTrace();
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            try {
                if (stmt != null)
                    stmt.close();
                if (conn != null)
                    conn.close();
            } catch (SQLException se) {
                se.printStackTrace();
            }
        }
        System.out.println("Goodbye!");
    }

    private void saveEquations() {
        Connection conn = null;
        PreparedStatement pstmt = null;
        try {
            Class.forName("com.mysql.cj.jdbc.Driver");
            conn = DriverManager.getConnection(
                    "jdbc:mysql://localhost:3306/rjgzdatabase?characterEncoding=utf8&serverTimezone=Asia/Shanghai&useSSL=false",
                    "root", "Zqy173590939");

            for (Node node : flowPane.getChildren()) {
                if (node instanceof HBox) {
                    HBox equationBox = (HBox) node;
                    Label idLabel = (Label) equationBox.getChildren().get(0); // 获取算式ID标签
                    Label equationLabel = (Label) equationBox.getChildren().get(2);
                    TextField answerField = (TextField) equationBox.getChildren().get(3);

                    String equation = equationLabel.getText();
                    String answerText = answerField.getText();

                    // 检查答案字段是否为空
                    int answer = 0;
                    if (!answerText.isEmpty()) {
                        answer = Integer.parseInt(answerText);
                    }

                    // 计算正确结果
                    int result = calculateResult(equation);

                    // 保存到数据库
                    String sql = "INSERT INTO equationtable (id, Operand1, Operator, Operand2, Result) VALUES (?, ?, ?, ?, ?)";
                    pstmt = conn.prepareStatement(sql);
                    pstmt.setInt(1, Integer.parseInt(idLabel.getText())); // 将算式ID插入到数据库中
                    pstmt.setInt(2, getOperand1(equation));
                    pstmt.setString(3, getOperator(equation));
                    pstmt.setInt(4, getOperand2(equation));
                    pstmt.setInt(5, result);
                    pstmt.executeUpdate();
                }
            }

            System.out.println("算式保存成功!!!");
            showAlert("保存成功!");
        } catch (SQLException se) {
            se.printStackTrace();
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            try {
                if (pstmt != null)
                    pstmt.close();
                if (conn != null)
                    conn.close();
            } catch (SQLException se) {
                se.printStackTrace();
            }
        }
        System.out.println("Goodbye!");
    }



    private int calculateResult(String equation) {
        String[] parts = equation.split(" ");
        int operand1 = Integer.parseInt(parts[0]);
        int operand2 = Integer.parseInt(parts[2]);
        String operator = parts[1];

        int result = 0;
        switch (operator) {
            case "+":
                result = operand1 + operand2;
                break;
            case "-":
                result = operand1 - operand2;
                break;
            case "*":          //此处预设乘法和除法便于以后相应的添加功能
                result = operand1 * operand2;
                break;
            case "/":
                result = operand1 / operand2;
                break;
        }

        return result;
    }

    private int getOperand1(String equation) {
        String[] parts = equation.split(" ");
        return Integer.parseInt(parts[0]);
    }

    private String getOperator(String equation) {
        String[] parts = equation.split(" ");
        return parts[1];
    }

    private int getOperand2(String equation) {
        String[] parts = equation.split(" ");
        return Integer.parseInt(parts[2]);
    }

    private void showAlert(String message) {
        Alert alert = new Alert(Alert.AlertType.INFORMATION);
        alert.setTitle("提示信息");
        alert.setHeaderText(null);
        alert.setContentText(message);
        alert.showAndWait();
    }

    private void displayAllEquationsFromDatabase() {
        Connection conn = null;
        Statement stmt = null;
        try {
            Class.forName("com.mysql.cj.jdbc.Driver");
            conn = DriverManager.getConnection(
                    "jdbc:mysql://localhost:3306/rjgzdatabase?characterEncoding=utf8&serverTimezone=Asia/Shanghai&useSSL=false",
                    "root", "Zqy173590939");

            stmt = conn.createStatement();

            ResultSet rs = stmt.executeQuery("SELECT * FROM equationtable");
            if (!rs.next()) {
                showAlert("当前题库为空");
            } else {
                do {
                    int id = rs.getInt("id");
                    String equation = id + "、 " + rs.getInt("Operand1") + " " + rs.getString("Operator") + " " +
                            rs.getInt("Operand2") + " = " + rs.getInt("Result");
                    Label equationLabel = new Label(equation);
                    flowPane.getChildren().add(equationLabel);
                } while (rs.next());
            }

        } catch (SQLException se) {
            se.printStackTrace();
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            try {
                if (stmt != null)
                    stmt.close();
                if (conn != null)
                    conn.close();
            } catch (SQLException se) {
                se.printStackTrace();
            }
        }
        System.out.println("Goodbye!");
    }

    private void checkEquations() {
        int totalEquations = 0; // 总题数
        int correctAnswers = 0; // 答对题数
        int incorrectAnswers = 0; // 答错题数

        for (Node node : flowPane.getChildren()) {
            if (node instanceof HBox) {
                HBox equationBox = (HBox) node;
                Label equationLabel = (Label) equationBox.getChildren().get(2);
                TextField answerField = (TextField) equationBox.getChildren().get(3);
                String equation = equationLabel.getText();
                String answerText = answerField.getText();
                // 检查答案字段是否为空
                if (!answerText.isEmpty()) {
                    totalEquations++;
                    int userAnswer = Integer.parseInt(answerText);
                    int result = calculateResult(equation);
                    if (userAnswer == result) { // 答案正确
                        equationBox.setStyle("-fx-background-color: #99ff99"); // 设置背景色为绿色
                        correctAnswers++;
                    } else { // 答案错误
                        equationBox.setStyle("-fx-background-color: #ff9999"); // 设置背景色为红色
                        incorrectAnswers++;
                    }
                }
            }
        }

        double correctPercentage = (double) correctAnswers / totalEquations * 100;
        double incorrectPercentage = (double) incorrectAnswers / totalEquations * 100;

        infoTextArea.setText("统计信息:\n" +
                "总题数:" + totalEquations + "\n" +
                "正确题数:" + correctAnswers + "\n" +
                "错误题数:" + incorrectAnswers + "\n" +
                "正确率:" + String.format("%.2f", correctPercentage) + "%\n" +
                "错误率:" + String.format("%.2f", incorrectPercentage) + "%");
    }

    private void showAccuracyChart() {
        int totalEquations = 0; // 总题数
        int correctAnswers = 0; // 答对题数
        for (Node node : flowPane.getChildren()) {
            if (node instanceof HBox) {
                HBox equationBox = (HBox) node;
                Label equationLabel = (Label) equationBox.getChildren().get(2);
                TextField answerField = (TextField) equationBox.getChildren().get(3);
                String equation = equationLabel.getText();
                String answerText = answerField.getText();
                // 检查答案字段是否为空
                if (!answerText.isEmpty()) {
                    totalEquations++;
                    int userAnswer = Integer.parseInt(answerText);
                    int result = calculateResult(equation);
                    if (userAnswer == result) { // 答案正确
                        correctAnswers++;
                    }
                }
            }
        }
        // 创建一个饼状图数据
        double correctPercentage = (double) correctAnswers / totalEquations * 100;
        double incorrectPercentage = 100 - correctPercentage;

        infoTextArea.setText("统计信息:\n" +
                "总题数:" + totalEquations + "\n" +
                "正确题数:" + correctAnswers + "\n" +
                "错误题数:" + (totalEquations - correctAnswers) + "\n" +
                "正确率:" + String.format("%.2f", correctPercentage) + "%\n" +
                "错误率:" + String.format("%.2f", incorrectPercentage) + "%");

        // 创建饼状图并显示
        PieChart chart = new PieChart();
        ObservableList<PieChart.Data> pieChartData = FXCollections.observableArrayList(
                new PieChart.Data("Correct", correctAnswers),
                new PieChart.Data("Incorrect", totalEquations - correctAnswers)
        );
        chart.setData(pieChartData);
        chart.setTitle("Accuracy Chart");

        // 创建一个新的Stage来显示饼状图
        Stage chartStage = new Stage();
        chartStage.setScene(new Scene(chart, 600, 400));
        chartStage.show();
    }

    //为了使事件处理器的代码更简洁,刻意独立出了这个方法,没有具体意义
    private void deleteEquations() {
        // 读取数据库中所有题目展示到界面中
        flowPane.getChildren().clear();
        displayAllEquationsFromDatabase();

        // 创建一个警示对话框
        Dialog<Pair<String, String>> dialog = new Dialog<>();
        dialog.setTitle("删除算术式范围");
        dialog.setHeaderText(null);

        // 设置对话框的按钮
        ButtonType deleteButtonType = new ButtonType("删除", ButtonBar.ButtonData.OK_DONE);
        dialog.getDialogPane().getButtonTypes().addAll(deleteButtonType, ButtonType.CANCEL);

        // 创建并设置对话框的内容
        GridPane grid = new GridPane();
        grid.setHgap(10);
        grid.setVgap(10);
        grid.setPadding(new Insets(20, 150, 10, 10));

        TextField startIDTextField = new TextField();
        TextField endIDTextField = new TextField();

        grid.add(new Label("起始ID:"), 0, 0);
        grid.add(startIDTextField, 1, 0);
        grid.add(new Label("结束ID:"), 2, 0);
        grid.add(endIDTextField, 3, 0);

        dialog.getDialogPane().setContent(grid);

        // 点击删除按钮时的逻辑
        dialog.setResultConverter(dialogButton -> {
            if (dialogButton == deleteButtonType) {
                int startID = Integer.parseInt(startIDTextField.getText());
                int endID = Integer.parseInt(endIDTextField.getText());

                // 删除数据库中匹配的算术式
                deleteEquationsByRange(startID, endID);

                // 清空界面上的匹配的算术式
                for (Node node : flowPane.getChildren()) {
                    if (node instanceof HBox) {
                        HBox equationBox = (HBox) node;
                        Label idLabel = (Label) equationBox.getChildren().get(0); // 获取算式ID标签

                        int id = Integer.parseInt(idLabel.getText());
                        if (id >= startID && id <= endID) {
                            flowPane.getChildren().remove(equationBox);
                        }
                    }
                }

                showAlert("算术式删除成功!");
            }
            return null;
        });

        dialog.showAndWait();
    }

    private void deleteEquationsByRange(int startID, int endID) {
        Connection conn = null;
        PreparedStatement pstmt = null;
        try {
            Class.forName("com.mysql.cj.jdbc.Driver");
            conn = DriverManager.getConnection(
                    "jdbc:mysql://localhost:3306/rjgzdatabase?characterEncoding=utf8&serverTimezone=Asia/Shanghai&useSSL=false",
                    "root", "Zqy173590939");

            String sql = "DELETE FROM equationtable WHERE id >= ? AND id <= ?";
            pstmt = conn.prepareStatement(sql);
            pstmt.setInt(1, startID);
            pstmt.setInt(2, endID);
            pstmt.executeUpdate();
        } catch (SQLException se) {
            se.printStackTrace();
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            try {
                if (pstmt != null)
                    pstmt.close();
                if (conn != null)
                    conn.close();
            } catch (SQLException se) {
                se.printStackTrace();
            }
        }
        System.out.println("Goodbye!");
    }

    // 删除数据库中的所有算术式
    private void deleteAllEquations() {
        Connection conn = null;
        Statement stmt = null;
        try {
            Class.forName("com.mysql.cj.jdbc.Driver");
            conn = DriverManager.getConnection(
                    "jdbc:mysql://localhost:3306/rjgzdatabase?characterEncoding=utf8&serverTimezone=Asia/Shanghai&useSSL=false",
                    "root", "Zqy173590939");

            stmt = conn.createStatement();

            String sql = "DELETE FROM equationtable";
            stmt.executeUpdate(sql);
        } catch (SQLException se) {
            se.printStackTrace();
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            try {
                if (stmt != null)
                    stmt.close();
                if (conn != null)
                    conn.close();
            } catch (SQLException se) {
                se.printStackTrace();
            }
        }
        System.out.println("Goodbye!");
    }



}
现在数据库中新增了一个错题集表mistakesequationtable,表的结构跟equationtable完全一样,表中有
Operand1
Operator
Operand2
Result
ID
数据结构分别为:
int
char
int
int
int
,现在需要增加错题集功能,已经创建了错题集菜单栏和重做错题按钮,现在为Redo Mistakes Equations添加事件处理器。点击Redo Mistakes Equations后,弹出警示对话框,提示用户输入本次想要重做多少道错题,确认后则从错题集中随机抽取出相应的数目显示在界面中,要求这部分区别于读取习题,错误的题目用户可以重做,要有输入框,重做后也可检查对错和查看正确率。
要求修改checkequation的逻辑,使其链接数据库,点击check后,被判定为错题的题目直接保存在错题集表mistakesequationtable中,并且获取mistakesequationtable表中ID列的最大值从新赋予ID,如果表中为空则从1开始编号,如果错题集中有数据则从获取的最大值+1开始标号。
给出需要添加或修改的部分。
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2023-12-31 22:20:25 | 显示全部楼层
zqy173590939 发表于 2023-12-31 22:20
package com.example.javafxmw;

import gaijin3.*; ...


这是一个JavaFX应用程序,用于创建口算习题薄。它有以下功能:

1. 生成习题:通过对话框输入算式的数量,生成指定数量

以上回复来自 FishC AI 小助理,如未能正确解答您的问题,请继续追问。
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

 楼主| 发表于 2023-12-31 23:18:01 | 显示全部楼层
package com.example.javafxmw;

import gaijin3.*;
import javafx.application.Application;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.geometry.Insets;
import javafx.scene.Node;
import javafx.scene.Scene;
import javafx.scene.chart.PieChart;
import javafx.scene.control.*;
import javafx.scene.image.Image;
import javafx.scene.layout.BorderPane;
import javafx.scene.layout.FlowPane;
import javafx.scene.layout.GridPane;
import javafx.scene.layout.HBox;
import javafx.stage.Stage;
import javafx.util.Pair;

import java.io.IOException;
import java.sql.*;
import java.util.Optional;

public class HelloApplication extends Application
{
    // 定义全局变量
    //定义一个TextArea控件作为全局变量
    TextArea infoTextArea = new TextArea();

    Button viewAccuracyButton = new Button("View Accuracy");

    FlowPane flowPane = new FlowPane();
    ScrollPane scrollPane = new ScrollPane();// 创建一个滚动面板对象
    private int maxID = 0;

    @Override
    public void start(Stage stage) throws IOException {
        MenuItem generateMenuItem = new MenuItem("Generate");

        // 事件处理器代码
        generateMenuItem.setOnAction(new EventHandler<ActionEvent>() {
            @Override
            public void handle(ActionEvent event) {
                generateEquation();
            }
        });

        MenuItem saveMenuItem = new MenuItem("Save");

        saveMenuItem.setOnAction(new EventHandler<ActionEvent>() {
            @Override
            public void handle(ActionEvent event) {
                saveEquations();
                connectDatabase();
            }
        });

        MenuItem readMenuItem = new MenuItem("Read");

        readMenuItem.setOnAction(new EventHandler<ActionEvent>() {
            @Override
            public void handle(ActionEvent event) {
                flowPane.getChildren().clear(); // 清空当前GUI界面
                showAlert("习题已读取");
                displayAllEquationsFromDatabase();
            }
        });

        MenuItem checkMenuItem = new MenuItem("Check");

        checkMenuItem.setOnAction(new EventHandler<ActionEvent>() {
            @Override
            public void handle(ActionEvent event) {
                // 检查习题
                checkEquations();
            }
        });

        // View Accuracy按钮的点击事件监听器
        viewAccuracyButton.setOnAction(new EventHandler<ActionEvent>() {
            @Override
            public void handle(ActionEvent event) {
                // 显示饼状图
                showAccuracyChart();
            }
        });

        MenuItem deleteMenuItem = new MenuItem("Delete by serial number");

        // Delete by serial number按钮的点击事件监听器,部分删除算数式
        deleteMenuItem.setOnAction(new EventHandler<ActionEvent>() {
            @Override
            public void handle(ActionEvent event) {
                deleteEquations();
            }
        });

        MenuItem deleteMenuItem1 = new MenuItem("Delete all");

        // Delete all按钮的点击事件监听器,全部删除
        deleteMenuItem1.setOnAction(new EventHandler<ActionEvent>() {
            @Override
            public void handle(ActionEvent event) {
                // 删除数据库中的所有算术式
                deleteAllEquations();

                // 清空界面上的所有算术式
                flowPane.getChildren().clear();

                showAlert("所有算术式删除成功!");
            }
        });

        MenuItem mistakesEquationsCollection = new MenuItem("Redo Mistakes Equations");

        Menu fileMenu = new Menu("File");
        Menu saveMenu = new Menu("SaveEquation");
        Menu readMenu = new Menu("ReadEquation");
        Menu checkMenu = new Menu("CheckEquation");
        Menu deleteMenu = new Menu("Delete");
        Menu mistakesEquationsCollectionMenu = new Menu("MistakesEquationsCollection");

        fileMenu.getItems().addAll(generateMenuItem);
        saveMenu.getItems().add(saveMenuItem);
        readMenu.getItems().add(readMenuItem);
        checkMenu.getItems().add(checkMenuItem);
        deleteMenu.getItems().addAll(deleteMenuItem,deleteMenuItem1);
        mistakesEquationsCollectionMenu.getItems().add(mistakesEquationsCollection);

        MenuBar menuBar = new MenuBar();
        menuBar.getMenus().addAll(fileMenu);
        menuBar.getMenus().add(saveMenu);
        menuBar.getMenus().add(readMenu);
        menuBar.getMenus().add(checkMenu);
        menuBar.getMenus().add(deleteMenu);
        menuBar.getMenus().add(mistakesEquationsCollectionMenu);

        flowPane.setHgap(50);
        flowPane.setVgap(30);
        flowPane.setPadding(new Insets(20));
        flowPane.setPrefSize(800, 560); // 设置 FlowPane 的大小

        BorderPane borderPane = new BorderPane();
        borderPane.setTop(menuBar);
        borderPane.setCenter(flowPane);

        //为了解决题目生成或多flowpane没有拖动条无法显示的问题
        // 将FlowPane放在一个ScrollPane中
        scrollPane.setContent(flowPane);// 设置滚动面板的内容为 flowPane,即将 flowPane 放入滚动面板中
        scrollPane.setFitToHeight(true);// 可以让滚动面板的高度自适应内容的高度
        borderPane.setCenter(scrollPane); // 将ScrollPane放置在中心位置

        HBox bottomBox = new HBox(10, viewAccuracyButton);
        HBox.setMargin(viewAccuracyButton, new Insets(50, 0, 20, 140));
        borderPane.setBottom(bottomBox);

        Scene scene = new Scene(borderPane, 800, 640);
        stage.setTitle("口算习题薄");
        stage.setScene(scene);
        stage.show();

        infoTextArea.setPrefSize(400, 110);
        //将TextArea控件其设置为只读
        infoTextArea.setEditable(false);

        HBox showbottomBox = new HBox(140, viewAccuracyButton, infoTextArea);
        HBox.setMargin(infoTextArea, new Insets(20, 0, 20, 0));
        borderPane.setBottom(showbottomBox);


    }


    public static void main(String[] args) {
        launch();
    }

    //为了使generate的事件处理器更美观特意拉出了这个类
    public EquationCollection generateEquation() {
        // 创建一个警示对话框
        TextInputDialog dialog = new TextInputDialog("5");
        dialog.setTitle("请输入算式数量");
        dialog.setHeaderText(null);
        dialog.setContentText("算式数量:");

        // 显示对话框,并获取用户输入的算式数量
        Optional<String> result = dialog.showAndWait();
        if (result.isPresent())
        {
            int n = Integer.parseInt(result.get());

            // 生成算式
            EquationCollection equationCollection = generateEquations(n);

            // 清空之前的内容
            flowPane.getChildren().clear();

            // 遍历算式集合并显示在GUI中
            for (IEquation equation : equationCollection)
            {
                maxID++; // id自增
                Label idLabel = new Label(String.valueOf(maxID)); // 获取当前最大ID,并将新的算式ID设为其加1
                Label equationLabel = new Label(equation.toString());
                TextField answerField = new TextField(); // 创建一个新的文本框
                HBox equationBox = new HBox(10, idLabel, new Label("、"), equationLabel, answerField); // 将算式ID标签、顿号、算式标签和文本框放入水平布局
                flowPane.getChildren().add(equationBox); // 将水平布局添加到 flowPane 中
            }

            // 连接数据库
            connectDatabase();
        }
        return null;
    }

    // 生成算式的方法
    public EquationCollection generateEquations(int n) {
        EquationCollection equationCollection = new EquationCollection();
        EquationCheckerOfRange equationChecker = new EquationCheckerOfRange(0, 100);
        equationCollection.generate(n, equationChecker);
        return equationCollection;
    }

    // 连接数据库的方法
    public void connectDatabase() {
        Connection conn = null;
        Statement stmt = null;
        try {
            Class.forName("com.mysql.cj.jdbc.Driver");
            conn = DriverManager.getConnection(
                    "jdbc:mysql://localhost:3306/rjgzdatabase?characterEncoding=utf8&serverTimezone=Asia/Shanghai&useSSL=false",
                    "root", "Zqy173590939");

            DatabaseMetaData dbMeta = conn.getMetaData();
            System.out.println("当前用户:" + dbMeta.getUserName());
            System.out.println("驱动版本:" + dbMeta.getDriverVersion());
            System.out.println("MySQL版本:" + dbMeta.getDatabaseProductVersion());

            stmt = conn.createStatement();

            // 查询最大ID值
            ResultSet rs = stmt.executeQuery("SELECT MAX(id) FROM equationtable");
            if (rs.next()) {
                maxID = rs.getInt(1);
            }

        } catch (SQLException se) {
            se.printStackTrace();
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            try {
                if (stmt != null)
                    stmt.close();
                if (conn != null)
                    conn.close();
            } catch (SQLException se) {
                se.printStackTrace();
            }
        }
        System.out.println("Goodbye!");
    }

    private void saveEquations() {
        Connection conn = null;
        PreparedStatement pstmt = null;
        try {
            Class.forName("com.mysql.cj.jdbc.Driver");
            conn = DriverManager.getConnection(
                    "jdbc:mysql://localhost:3306/rjgzdatabase?characterEncoding=utf8&serverTimezone=Asia/Shanghai&useSSL=false",
                    "root", "Zqy173590939");

            for (Node node : flowPane.getChildren()) {
                if (node instanceof HBox) {
                    HBox equationBox = (HBox) node;
                    Label idLabel = (Label) equationBox.getChildren().get(0); // 获取算式ID标签
                    Label equationLabel = (Label) equationBox.getChildren().get(2);
                    TextField answerField = (TextField) equationBox.getChildren().get(3);

                    String equation = equationLabel.getText();
                    String answerText = answerField.getText();

                    // 检查答案字段是否为空
                    int answer = 0;
                    if (!answerText.isEmpty()) {
                        answer = Integer.parseInt(answerText);
                    }

                    // 计算正确结果
                    int result = calculateResult(equation);

                    // 保存到数据库
                    String sql = "INSERT INTO equationtable (id, Operand1, Operator, Operand2, Result) VALUES (?, ?, ?, ?, ?)";
                    pstmt = conn.prepareStatement(sql);
                    pstmt.setInt(1, Integer.parseInt(idLabel.getText())); // 将算式ID插入到数据库中
                    pstmt.setInt(2, getOperand1(equation));
                    pstmt.setString(3, getOperator(equation));
                    pstmt.setInt(4, getOperand2(equation));
                    pstmt.setInt(5, result);
                    pstmt.executeUpdate();
                }
            }

            System.out.println("算式保存成功!!!");
            showAlert("保存成功!");
        } catch (SQLException se) {
            se.printStackTrace();
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            try {
                if (pstmt != null)
                    pstmt.close();
                if (conn != null)
                    conn.close();
            } catch (SQLException se) {
                se.printStackTrace();
            }
        }
        System.out.println("Goodbye!");
    }



    private int calculateResult(String equation) {
        String[] parts = equation.split(" ");
        int operand1 = Integer.parseInt(parts[0]);
        int operand2 = Integer.parseInt(parts[2]);
        String operator = parts[1];

        int result = 0;
        switch (operator) {
            case "+":
                result = operand1 + operand2;
                break;
            case "-":
                result = operand1 - operand2;
                break;
            case "*":          //此处预设乘法和除法便于以后相应的添加功能
                result = operand1 * operand2;
                break;
            case "/":
                result = operand1 / operand2;
                break;
        }

        return result;
    }

    private int getOperand1(String equation) {
        String[] parts = equation.split(" ");
        return Integer.parseInt(parts[0]);
    }

    private String getOperator(String equation) {
        String[] parts = equation.split(" ");
        return parts[1];
    }

    private int getOperand2(String equation) {
        String[] parts = equation.split(" ");
        return Integer.parseInt(parts[2]);
    }

    private void showAlert(String message) {
        Alert alert = new Alert(Alert.AlertType.INFORMATION);
        alert.setTitle("提示信息");
        alert.setHeaderText(null);
        alert.setContentText(message);
        alert.showAndWait();
    }

    private void displayAllEquationsFromDatabase() {
        Connection conn = null;
        Statement stmt = null;
        try {
            Class.forName("com.mysql.cj.jdbc.Driver");
            conn = DriverManager.getConnection(
                    "jdbc:mysql://localhost:3306/rjgzdatabase?characterEncoding=utf8&serverTimezone=Asia/Shanghai&useSSL=false",
                    "root", "Zqy173590939");

            stmt = conn.createStatement();

            ResultSet rs = stmt.executeQuery("SELECT * FROM equationtable");
            if (!rs.next()) {
                showAlert("当前题库为空");
            } else {
                do {
                    int id = rs.getInt("id");
                    String equation = id + "、 " + rs.getInt("Operand1") + " " + rs.getString("Operator") + " " +
                            rs.getInt("Operand2") + " = " + rs.getInt("Result");
                    Label equationLabel = new Label(equation);
                    flowPane.getChildren().add(equationLabel);
                } while (rs.next());
            }

        } catch (SQLException se) {
            se.printStackTrace();
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            try {
                if (stmt != null)
                    stmt.close();
                if (conn != null)
                    conn.close();
            } catch (SQLException se) {
                se.printStackTrace();
            }
        }
        System.out.println("Goodbye!");
    }

    private void checkEquations() {
        int totalEquations = 0; // 总题数
        int correctAnswers = 0; // 答对题数
        int incorrectAnswers = 0; // 答错题数

        for (Node node : flowPane.getChildren()) {
            if (node instanceof HBox) {
                HBox equationBox = (HBox) node;
                Label equationLabel = (Label) equationBox.getChildren().get(2);
                TextField answerField = (TextField) equationBox.getChildren().get(3);
                String equation = equationLabel.getText();
                String answerText = answerField.getText();
                // 检查答案字段是否为空
                if (!answerText.isEmpty()) {
                    totalEquations++;
                    int userAnswer = Integer.parseInt(answerText);
                    int result = calculateResult(equation);
                    if (userAnswer == result) { // 答案正确
                        equationBox.setStyle("-fx-background-color: #99ff99"); // 设置背景色为绿色
                        correctAnswers++;
                    } else { // 答案错误
                        equationBox.setStyle("-fx-background-color: #ff9999"); // 设置背景色为红色
                        incorrectAnswers++;
                    }
                }
            }
        }

        double correctPercentage = (double) correctAnswers / totalEquations * 100;
        double incorrectPercentage = (double) incorrectAnswers / totalEquations * 100;

        infoTextArea.setText("统计信息:\n" +
                "总题数:" + totalEquations + "\n" +
                "正确题数:" + correctAnswers + "\n" +
                "错误题数:" + incorrectAnswers + "\n" +
                "正确率:" + String.format("%.2f", correctPercentage) + "%\n" +
                "错误率:" + String.format("%.2f", incorrectPercentage) + "%");
    }

    private void showAccuracyChart() {
        int totalEquations = 0; // 总题数
        int correctAnswers = 0; // 答对题数
        for (Node node : flowPane.getChildren()) {
            if (node instanceof HBox) {
                HBox equationBox = (HBox) node;
                Label equationLabel = (Label) equationBox.getChildren().get(2);
                TextField answerField = (TextField) equationBox.getChildren().get(3);
                String equation = equationLabel.getText();
                String answerText = answerField.getText();
                // 检查答案字段是否为空
                if (!answerText.isEmpty()) {
                    totalEquations++;
                    int userAnswer = Integer.parseInt(answerText);
                    int result = calculateResult(equation);
                    if (userAnswer == result) { // 答案正确
                        correctAnswers++;
                    }
                }
            }
        }
        // 创建一个饼状图数据
        double correctPercentage = (double) correctAnswers / totalEquations * 100;
        double incorrectPercentage = 100 - correctPercentage;

        infoTextArea.setText("统计信息:\n" +
                "总题数:" + totalEquations + "\n" +
                "正确题数:" + correctAnswers + "\n" +
                "错误题数:" + (totalEquations - correctAnswers) + "\n" +
                "正确率:" + String.format("%.2f", correctPercentage) + "%\n" +
                "错误率:" + String.format("%.2f", incorrectPercentage) + "%");

        // 创建饼状图并显示
        PieChart chart = new PieChart();
        ObservableList<PieChart.Data> pieChartData = FXCollections.observableArrayList(
                new PieChart.Data("Correct", correctAnswers),
                new PieChart.Data("Incorrect", totalEquations - correctAnswers)
        );
        chart.setData(pieChartData);
        chart.setTitle("Accuracy Chart");

        // 创建一个新的Stage来显示饼状图
        Stage chartStage = new Stage();
        chartStage.setScene(new Scene(chart, 600, 400));
        chartStage.show();
    }

    //为了使事件处理器的代码更简洁,刻意独立出了这个方法,没有具体意义
    private void deleteEquations() {
        // 读取数据库中所有题目展示到界面中
        flowPane.getChildren().clear();
        displayAllEquationsFromDatabase();

        // 创建一个警示对话框
        Dialog<Pair<String, String>> dialog = new Dialog<>();
        dialog.setTitle("删除算术式范围");
        dialog.setHeaderText(null);

        // 设置对话框的按钮
        ButtonType deleteButtonType = new ButtonType("删除", ButtonBar.ButtonData.OK_DONE);
        dialog.getDialogPane().getButtonTypes().addAll(deleteButtonType, ButtonType.CANCEL);

        // 创建并设置对话框的内容
        GridPane grid = new GridPane();
        grid.setHgap(10);
        grid.setVgap(10);
        grid.setPadding(new Insets(20, 150, 10, 10));

        TextField startIDTextField = new TextField();
        TextField endIDTextField = new TextField();

        grid.add(new Label("起始ID:"), 0, 0);
        grid.add(startIDTextField, 1, 0);
        grid.add(new Label("结束ID:"), 2, 0);
        grid.add(endIDTextField, 3, 0);

        dialog.getDialogPane().setContent(grid);

        // 点击删除按钮时的逻辑
        dialog.setResultConverter(dialogButton -> {
            if (dialogButton == deleteButtonType) {
                int startID = Integer.parseInt(startIDTextField.getText());
                int endID = Integer.parseInt(endIDTextField.getText());

                // 删除数据库中匹配的算术式
                deleteEquationsByRange(startID, endID);

                // 清空界面上的匹配的算术式
                for (Node node : flowPane.getChildren()) {
                    if (node instanceof HBox) {
                        HBox equationBox = (HBox) node;
                        Label idLabel = (Label) equationBox.getChildren().get(0); // 获取算式ID标签

                        int id = Integer.parseInt(idLabel.getText());
                        if (id >= startID && id <= endID) {
                            flowPane.getChildren().remove(equationBox);
                        }
                    }
                }

                showAlert("算术式删除成功!");
            }
            return null;
        });

        dialog.showAndWait();
    }

    private void deleteEquationsByRange(int startID, int endID) {
        Connection conn = null;
        PreparedStatement pstmt = null;
        try {
            Class.forName("com.mysql.cj.jdbc.Driver");
            conn = DriverManager.getConnection(
                    "jdbc:mysql://localhost:3306/rjgzdatabase?characterEncoding=utf8&serverTimezone=Asia/Shanghai&useSSL=false",
                    "root", "Zqy173590939");

            String sql = "DELETE FROM equationtable WHERE id >= ? AND id <= ?";
            pstmt = conn.prepareStatement(sql);
            pstmt.setInt(1, startID);
            pstmt.setInt(2, endID);
            pstmt.executeUpdate();
        } catch (SQLException se) {
            se.printStackTrace();
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            try {
                if (pstmt != null)
                    pstmt.close();
                if (conn != null)
                    conn.close();
            } catch (SQLException se) {
                se.printStackTrace();
            }
        }
        System.out.println("Goodbye!");
    }

    // 删除数据库中的所有算术式
    private void deleteAllEquations() {
        Connection conn = null;
        Statement stmt = null;
        try {
            Class.forName("com.mysql.cj.jdbc.Driver");
            conn = DriverManager.getConnection(
                    "jdbc:mysql://localhost:3306/rjgzdatabase?characterEncoding=utf8&serverTimezone=Asia/Shanghai&useSSL=false",
                    "root", "Zqy173590939");

            stmt = conn.createStatement();

            String sql = "DELETE FROM equationtable";
            stmt.executeUpdate(sql);
        } catch (SQLException se) {
            se.printStackTrace();
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            try {
                if (stmt != null)
                    stmt.close();
                if (conn != null)
                    conn.close();
            } catch (SQLException se) {
                se.printStackTrace();
            }
        }
        System.out.println("Goodbye!");
    }



}
现在数据库中新增了一个错题集表mistakesequationtable,表的结构跟equationtable完全一样,表中有
Operand1
Operator
Operand2
Result
ID
数据结构分别为:
int
char
int
int
int
,现在需要增加错题集功能,已经创建了错题集菜单栏和重做错题按钮,现在为Redo Mistakes Equations添加事件处理器。点击Redo Mistakes Equations后,弹出警示对话框,提示用户输入本次想要重做多少道错题,确认后则从错题集中随机抽取出相应的数目显示在界面中,要求这部分区别于读取习题,错误的题目用户可以重做,重做的题目展示时要有textfield,重做后也可检查对错和查看正确率。
要求修改checkequation的逻辑,使其链接数据库,点击check后,被判定为错题的题目直接保存在错题集表mistakesequationtable中,错题集表mistakesequationtable表的ID列已被我设置为自增,顺序存入即可。
给出需要添加或修改的部分。
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2023-12-31 23:18:11 | 显示全部楼层
zqy173590939 发表于 2023-12-31 23:18
package com.example.javafxmw;

import gaijin3.*; ...


很抱歉,您可能因为复制粘贴的原因导致代码截断。根据您提供的代码片段,我发现该应用程序是使用JavaFX

以上回复来自 FishC AI 小助理,如未能正确解答您的问题,请继续追问。
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

小黑屋|手机版|Archiver|鱼C工作室 ( 粤ICP备18085999号-1 | 粤公网安备 44051102000585号)

GMT+8, 2024-4-28 08:21

Powered by Discuz! X3.4

© 2001-2023 Discuz! Team.

快速回复 返回顶部 返回列表