软件构造大作业之计算题生成器

本次GUI界面采有java的swing包,相比于awt,swing为重量级GUI插件包,是目前大多数Java编写GUI界面普遍使用的包,后台连接了mysql数据库可以实现计算题的保存

 

 

计算题生成类

package com.std.www.compute;

import java.io.BufferedWriter;
import java.io.FileWriter;
import java.io.IOException;
import java.time.LocalDateTime;
import java.util.*;

public class TopicProduce {
    private static Set<String> flag=new HashSet<>();
    private static List<Topic> topicList=new ArrayList<>();
    private static int numbering=0;
    public static Set<String> getFlag() {
        return flag;
    }

    public static void setFlag(Set<String> flag) {
        TopicProduce.flag = flag;
    }

    public static List<Topic> getTopicList() {
        return topicList;
    }

    public static void setTopicList(List<Topic> topicList) {
        TopicProduce.topicList = topicList;
    }

    public static int getNumbering() {
        return numbering;
    }

    public static void setNumbering(int numbering) {
        TopicProduce.numbering = numbering;
    }

    private static String makeOp(List<String> op){
        Random random=new Random();
        return op.get(random.nextInt(10000)% op.size());
    }
    private static int makeNum(int minNum,int maxNum){
        Random random=new Random();
        return random.nextInt(maxNum-minNum+1)+minNum;
    }
    public static void makeTopic(int topicNum,List<String> topicLevel,int topicMinNum,int topicMaxNum,int opNum){
        numbering=1;
        topicList.clear();
        if(opNum<2) opNum=2;
        LocalDateTime localDateTime=LocalDateTime.now();
        System.out.println("题目难度等级:"+topicLevel);
        System.out.println("题目数量:"+topicNum);
        System.out.println("操作符个数:"+opNum);
        System.out.println("数值范围:"+topicMinNum+"~"+topicMaxNum);
        while (topicNum-->0) {
            List<String> symbols = new ArrayList<>();
            List<Integer> figures = new ArrayList<>();
            StringBuilder formula=new StringBuilder();
            for(int i=0;i<opNum;i++){
                if(i==0) {
                    int figure= makeNum(topicMinNum,topicMaxNum);
                    figures.add(figure);
                    formula.append(String.valueOf(figure));
                }
                String symbol=makeOp(topicLevel);
                int figure= makeNum(topicMinNum,topicMaxNum);
                if(figure==0&&symbol.equals("/")){
                    i--;
                    continue;
                }
                symbols.add(symbol);
                figures.add(figure);
                formula.append(" "+symbol+" ");
                formula.append(String.valueOf(figure));
            }
            formula.append("=");
            if(flag.contains(String.valueOf(formula))){
                topicNum++;
            }
            else {
                flag.add(String.valueOf(formula));
                Topic topic=new Topic(symbols,figures,String.valueOf(formula),numbering++,0);
                topic.setGroup_id(localDateTime);
                if(!topic.makeAnswer()){
                    topicNum++;
                    continue;
                }
                int ans=topic.getTopicAnswer();
                topic.setTopicAnswer(ans);
                topicList.add(topic);
            }

        }

    }
}
class Topic{
    private List<String> symbols;
    private List<Integer> figures;
    private String formula;
    private int topicId;
    private int topicAnswer;
    private LocalDateTime group_id;
    public Topic() {
    }

    public Topic(List<String> symbols, List<Integer> figures, String formula, int topicId, int topicAnswer) {
        this.symbols = symbols;
        this.figures = figures;
        this.formula = formula;
        this.topicId = topicId;
        this.topicAnswer = topicAnswer;
    }

    public Topic(String formula, int topicId, int topicAnswer,LocalDateTime group_id) {
        this.formula = formula;
        this.topicId = topicId;
        this.topicAnswer = topicAnswer;
        this.group_id = group_id;
    }

    public LocalDateTime getGroup_id() {
        return group_id;
    }

    public void setGroup_id(LocalDateTime group_id) {
        this.group_id = group_id;
    }

    public List<String> getSymbols() {
        return symbols;
    }

    public void setSymbols(List<String> symbols) {
        this.symbols = symbols;
    }

    public List<Integer> getFigures() {
        return figures;
    }

    public void setFigures(List<Integer> figures) {
        this.figures = figures;
    }

    public String getFormula() {
        return formula;
    }

    public void setFormula(String formula) {
        this.formula = formula;
    }

    public int getTopicId() {
        return topicId;
    }

    public void setTopicId(int topicId) {
        this.topicId = topicId;
    }

    public int getTopicAnswer() {
        return topicAnswer;
    }

    public void setTopicAnswer(int topicAnswer) {
        this.topicAnswer = topicAnswer;
    }
    private boolean check(String a,String b){
        if(a.equals("+")&&!b.equals("+")) return true;
        else if(a.equals("-")&&(b.equals("/")||b.equals("*"))) return true;
        else if(a.equals("*")&&b.equals("/")) return true;
        else return false;
    }
    private int computeAnswer(int x,int y,String op){
        switch (op){
            case "+":
                return x+y;
            case "-":
                return x-y;
            case "*":
                return x*y;
            case "/":
                return x/y;
            default:
                throw new RuntimeException("非法运算符");
        }
    }
    public boolean  makeAnswer(){
        Stack<String> sym_s=new Stack<>();
        Stack<Integer> fig_s=new Stack<>();
        fig_s.push(figures.get(0));
        for(int i=1;i<figures.size();i++){
            int fi=figures.get(i);
            String sy=symbols.get(i-1);
            if(sym_s.isEmpty()||check(sym_s.peek(),sy)){
                sym_s.push(sy);
                fig_s.push(fi);
            }
            else{
                while (!sym_s.isEmpty()&&!check(sym_s.peek(),sy)) {
                    int y = fig_s.pop();
                    int x = fig_s.pop();
                    String op=sym_s.pop();
                    if(op.equals("/")&&y==0){
                        System.out.println("除0异常");
                        return false;
                    }
                    int ans=computeAnswer(x,y,op);
                    fig_s.push(ans);
                }
                sym_s.push(sy);
                fig_s.push(fi);
            }
        }
        while (!sym_s.isEmpty()) {
            int y = fig_s.pop();
            int x = fig_s.pop();
            String op=sym_s.pop();
            if(op.equals("/")&&y==0){
                System.out.println("除0异常");
                return false;
            }
            int ans=computeAnswer(x,y,op);
            fig_s.push(ans);
        }
        this.setTopicAnswer(fig_s.pop());
        return true;
    }
}

GUI界面类

package com.std.www.compute;

import javax.swing.*;
import javax.swing.table.TableCellEditor;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;

public class TextFieldCellEditor extends AbstractCellEditor implements TableCellEditor {
    private JTextField textField;

    public TextFieldCellEditor() {
        textField = new JTextField();
        textField.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                stopCellEditing();
            }
        });
    }

    @Override
    public Object getCellEditorValue() {
        return textField.getText();
    }

    @Override
    public Component getTableCellEditorComponent(JTable table, Object value, boolean isSelected, int row, int column) {
        textField.setText((value != null) ? value.toString() : "");
        return textField;
    }
}
package com.std.www.compute;

import javax.swing.*;
import javax.swing.table.TableCellRenderer;
import java.awt.*;

public class TextFieldCellRenderer extends JTextField implements TableCellRenderer {
    public TextFieldCellRenderer() {
        setBorder(BorderFactory.createEmptyBorder());
    }

    @Override
    public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) {
        setText((value != null) ? value.toString() : "");
        return this;
    }
}
package com.std.www.compute;

import javafx.scene.web.WebEngine;

import javax.swing.*;
import javax.swing.border.LineBorder;
import javax.swing.table.DefaultTableModel;
import javax.swing.text.AbstractDocument;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.ArrayList;

import java.util.List;

public class TopicGUI {
    private static JScrollPane scrollPane;
    private static JTable topicTable;
    private static JTextField topicNum;
    private static JTextField minNum;
    private static JTextField maxNum;
    private static JTextField opNum;
    private static List<Topic> topics = new ArrayList<>();
    private static List<JTextField> answer = new ArrayList<>();
    private static DefaultTableModel model;
    private static JCheckBox checkBox1;
    private static JCheckBox checkBox2;
    private static JCheckBox checkBox3;
    private static JCheckBox checkBox4;
    private static  void loadTopicTable(){
        String[] columnNames = {"题目序号","题目","你的答案"};
        model = new DefaultTableModel(null, columnNames) {
            @Override
            public boolean isCellEditable(int row, int column) {
                return column == getColumnCount() - 1;
            }
        };
        topicTable.setModel(model);
        topicTable.getColumnModel().getColumn(columnNames.length - 1).setCellRenderer(new TextFieldCellRenderer());
        topicTable.getColumnModel().getColumn(columnNames.length - 1).setCellEditor(new TextFieldCellEditor());
        for (Topic i:topics){
            model.addRow(new Object[]{i.getTopicId(),i.getFormula(),""});
        }

    }

    private static void createAndShowGUI() {
        JFrame frame = new JFrame("算术题生成器");
        frame.setSize(1000, 800);
        frame.setLayout(null);
        frame.setLocationRelativeTo(null);
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        Font font = new Font("宋体", Font.BOLD, 25);
        //初始化头部
        JPanel headPanel = new JPanel();
        headPanel.setBackground(Color.WHITE);
        headPanel.setBounds(200, 50, 600, 150);
        headPanel.setLayout(new FlowLayout(FlowLayout.LEADING, 20, 10));
        JLabel numTopicLabel = new JLabel("题目数量");
        numTopicLabel.setFont(font);
        topicNum = new JTextField();
        topicNum.setPreferredSize(new Dimension(130, 30));
        JLabel numOpLabel = new JLabel("运算符个数");
        numOpLabel.setFont(font);
        opNum = new JTextField();
        opNum.setPreferredSize(new Dimension(130, 30));
        JLabel oPLabel = new JLabel("操作符");
        oPLabel.setFont(font);
        checkBox1 = new JCheckBox("+");
        checkBox2 = new JCheckBox("-");
        checkBox3 = new JCheckBox("*");
        checkBox4 = new JCheckBox("/");
        checkBox1.setFont(font);
        checkBox2.setFont(font);
        checkBox3.setFont(font);
        checkBox4.setFont(font);
        JLabel range = new JLabel("数值范围");
        range.setFont(font);
        minNum = new JTextField();
        minNum.setText("0");
        minNum.setPreferredSize(new Dimension(130, 30));
        maxNum = new JTextField();
        maxNum.setPreferredSize(new Dimension(130, 30));
        maxNum.setText("100");
        headPanel.add(numTopicLabel);
        headPanel.add(topicNum);
        headPanel.add(numOpLabel);
        headPanel.add(opNum);
        headPanel.add(oPLabel);
        headPanel.add(checkBox1);
        headPanel.add(checkBox2);
        headPanel.add(checkBox3);
        headPanel.add(checkBox4);
        JLabel jLabel = new JLabel();
        jLabel.setPreferredSize(new Dimension(200, 50));
        headPanel.add(jLabel);
        headPanel.add(range);
        headPanel.add(minNum);
        headPanel.add(maxNum);
        headPanel.setBorder(new LineBorder(Color.BLACK));


        //初始化计算题
        topicTable=new JTable();
        scrollPane=new JScrollPane(topicTable);
        scrollPane.setBounds(200,210,600,400);
        scrollPane.setBorder(new LineBorder(Color.BLUE));

        //初始化按钮
        JPanel buttonPanel=new JPanel();
        buttonPanel.setLayout(new BoxLayout(buttonPanel,BoxLayout.X_AXIS));
        buttonPanel.setBorder(new LineBorder(Color.BLUE));
        buttonPanel.setBounds(200,650,600,70);
        JButton push=new JButton("提交习题");
        push.setFont(font);
        JButton makeTopicButton=new JButton("生成习题");
        makeTopicButton.setFont(font);
        JButton saveTopicButton=new JButton("保存习题");
        saveTopicButton.setFont(font);
        JButton oldTopicButton=new JButton("历史习题");
        oldTopicButton.setFont(font);

        push.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                int rowCount = model.getRowCount();
                int lastColumnIndex = model.getColumnCount() - 1;
                StringBuilder stringBuilder=new StringBuilder("");
                int right=0;
                for (int row = 0; row < rowCount; row++) {
                    Object value = model.getValueAt(row, lastColumnIndex);
                    stringBuilder.append("答案: "+topics.get(row).getTopicAnswer()+" 你的答案: "+value+"\n");
                    if(String.valueOf(topics.get(row).getTopicAnswer()).equals(value)){
                        right++;
                    }
                }
                stringBuilder.append("正确率为: "+right*1.0/rowCount);
                JOptionPane.showMessageDialog(frame, stringBuilder.toString());
            }
        });

        makeTopicButton.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                List<String> op=new ArrayList<>();
                if(checkBox1.isSelected()){
                    op.add("+");
                }
                if(checkBox2.isSelected()){
                    op.add("-");
                }
                if(checkBox3.isSelected()){
                    op.add("*");
                }
                if(checkBox4.isSelected()){
                    op.add("/");
                }
                TopicProduce.makeTopic(Integer.parseInt(topicNum.getText()), op,Integer.parseInt(minNum.getText()),Integer.parseInt(maxNum.getText()),Integer.parseInt(opNum.getText()));
                topics=TopicProduce.getTopicList();
                loadTopicTable();
            }
        });
        saveTopicButton.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                TopicMysql topicMysql=new TopicMysql();
                if(topicMysql.saveTopics(topics)){
                    JOptionPane.showMessageDialog(frame, "保存成功");
                }
                else {
                    JOptionPane.showMessageDialog(frame, "保存失败");
                }
            }
        });
        oldTopicButton.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                TopicMysql topicMysql=new TopicMysql();
                topics.clear();
                topics=topicMysql.oldTopics();
                loadTopicTable();
            }
        });
        buttonPanel.add(push);
        buttonPanel.add(Box.createHorizontalGlue());
        buttonPanel.add(makeTopicButton);
        buttonPanel.add(Box.createHorizontalGlue());
        buttonPanel.add(saveTopicButton);
        buttonPanel.add(Box.createHorizontalGlue());
        buttonPanel.add(oldTopicButton);

        frame.add(headPanel);
        frame.add(scrollPane);
        frame.add(buttonPanel);
        frame.setVisible(true);

    }

    public static void main(String[] args) {
        javax.swing.SwingUtilities.invokeLater(new Runnable() {
            public void run() {
                createAndShowGUI();
            }
        });
    }

}

数据库连接

package com.std.www.compute;

import lombok.SneakyThrows;

import java.sql.*;
import java.time.LocalDate;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;

public class TopicMysql {
    private Connection connection;
    @SneakyThrows
    public Connection getConnection() {
        Class.forName("com.mysql.jdbc.Driver");
        connection=DriverManager.getConnection("jdbc:mysql://localhost:3307/lab?useSSL=false","root","123456");
        return connection;
    }
    @SneakyThrows
    public boolean saveTopics(List<Topic> topics){
        getConnection();
        PreparedStatement p = connection.prepareStatement("insert into topic values (?,?,?,?)");
        boolean flag=true;
        for (Topic i:topics){
            p.setInt(1,i.getTopicId());
            p.setString(2,i.getFormula());
            p.setInt(3,i.getTopicAnswer());
            p.setTimestamp(4, Timestamp.valueOf(i.getGroup_id()));
            flag&=p.executeUpdate()>0;
        }
        p.close();
        connection.close();
        return flag;
    }
    @SneakyThrows
    public List<Topic> oldTopics(){
        getConnection();
        PreparedStatement p = connection.prepareStatement("select * from topic");
        ResultSet res = p.executeQuery();
        List<Topic> topics=new ArrayList<>();
        while (res.next()){
            topics.add(new Topic(res.getString(2),res.getInt(1),res.getInt(3), res.getTimestamp(4).toLocalDateTime()));
        }
        p.close();
        connection.close();
        return topics;
    }
}

从程序到软件

从用户的需求来讲,本程序缺乏许多功能,例如实现小数或者更高级的运算题,对于历史错题的记录,对于历史生成题目进行分组展示可以让用户自由选择某一套习题,也没有实现题目去重,还有对每一道错题的错误次数统计,如果更加深入的话,还可以增加一种算法,根据以往用户的答题记录,优化生成,尽可能生成用户错误次数的题目的相似的题目类型,还有等等

从测试的角度来讲的话,本程序也缺乏健壮性,对于错误的输入没有判定,没有判定用户空选的情况,还有等等

软件构造课让我明白,软件不单单是实现功能,更关键的是用户体验,永远是为人服务的,最需要抓住的是用户的直观感受和必要需求,这样才能让程序变为一个软件。

posted @ 2023-11-28 22:07  突破铁皮  阅读(44)  评论(0编辑  收藏  举报