结对编程

结对号数:

许晓烽:112号

黄明炜:97号

码云仓库:https://gitee.com/huhulong/JieDuiXiangMu

1.需求分析:

  (1)根据参数生成n个四则运算式,并且规定范围

  (2)设置语言中文或者英文

  (3)有计时功能,并且可以设置最长时间

  (4)文件保存题目并且知道答题情况

2.程序设计

  

3.代码展示:

目录结构:

(1)顶层容器代码(MainFrame):

package main;

import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;

import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTextArea;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;

import bean.Formula;
import param.Param;
import menu.MainMenuBar;

public class MainFrame extends JFrame{
	JPanel jpanel=new JPanel();
	MainMenuBar mainMenuBar=new MainMenuBar(this);//菜单
	ButtonLabel generatingItemButton=new ButtonLabel(Param.generatingItem);//生成按钮
	ButtonLabel beginButton=new ButtonLabel(Param.begin);//开始按钮
	TimeProgressBar timeProgressBar=new TimeProgressBar(this);
	JTextArea subjectArea=new JTextArea();//题目框
	JTextArea answerArea=new JTextArea();//答题区
	public ButtonLabel submitButton=new ButtonLabel(Param.submit);//提交按钮
	
	//构造函数
	public MainFrame(){
		init();
		mouseEvent();
		this.setJMenuBar(mainMenuBar);//添加菜单
		this.setTitle(Param.title);
		this.setSize(700,600);
		this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);//设置默认关闭窗口方式
		this.setLocationRelativeTo(null);//设置窗体相对居中
		this.setResizable(false);//设置窗口不可调整
		this.setVisible(true);//可视化
	}
	
	//初始化设置
	public void init(){
		this.setLayout(null);//设置空布局
		
		generatingItemButton.setBounds(20, 20, 100, 30);
		this.add(generatingItemButton);
		
		beginButton.setBounds(130, 20, 100, 30);
		this.add(beginButton);
		
		//进度条
		timeProgressBar.setBounds(400, 20, 250, 30);
		this.add(timeProgressBar);
		
		
		subjectArea.setEditable(false);
		//给试题框出现滚动条
		JScrollPane jssubjectArea=new JScrollPane(subjectArea);
		jssubjectArea.setBounds(20, 100, 600, 150);
		this.add(jssubjectArea);
		
		answerArea.setEditable(false);
		//给答题框加设滚动条
		JScrollPane jsanswerArea=new JScrollPane(answerArea);
		jsanswerArea.setBounds(20, 300, 600, 150);
		this.add(jsanswerArea);
		
		
		submitButton.setBounds(300, 480, 100, 30);
		this.add(submitButton);
		
		jpanel.setBounds(0, 0, 700, 1000);
		this.add(jpanel);
		
	}
	
	//给三个label按钮添加监听
	public void mouseEvent(){
		//生成试题的点击事件
		generatingItemButton.addMouseListener(new MouseAdapter() {
			@Override
			public void mousePressed(MouseEvent arg0) {
				subjectArea.setText("");
				File answersFile = new File("file/Answers.txt");
				FileWriter answersFw;
				for(int i=0;i<Param.number;i++){
					Formula formula = new Formula(Param.range);
					String aFormula = formula.getAFormula();
					subjectArea.append((i+1)+"."+aFormula+"\r\n");
					//将答案写入到答案文件中
					try {
						answersFw = new FileWriter(answersFile, true);
						BufferedWriter answersBw = new BufferedWriter(answersFw);			
						answersBw.write((i + 1) + "." + formula.getAnswser().toString());
	                    answersBw.newLine();
	                    answersBw.flush();
	                    answersBw.close();
					} catch (IOException e) {
						// TODO Auto-generated catch block
						e.printStackTrace();
					} 
				}
				//讲题目写入到文件中
				File exercisesFile = new File("file/Exercises.txt");
				String stirng=subjectArea.getText();
				FileWriter exercisesFw;
				try {
					exercisesFw = new FileWriter(exercisesFile, true);
					BufferedWriter exercisesBw = new BufferedWriter(exercisesFw);
					exercisesBw.write(stirng);
                    exercisesBw.flush();
                    exercisesBw.close();
				} catch (IOException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
			}
		});
		
		//开始写题的点击事件
		beginButton.addMouseListener(new MouseAdapter(){
			@Override
			public void mousePressed(MouseEvent arg0) {
				timeProgressBar.restart();
				answerArea.setEditable(true);
			}
		});
		
		//提交试题的点击事件
		submitButton.addMouseListener(new MouseAdapter(){
			@Override
			public void mousePressed(MouseEvent arg0) {
				File yourFile = new File("file/YourFile.txt");
				String string = answerArea.getText();
				FileWriter yourFileFw;
				try {
					yourFileFw = new FileWriter(yourFile, true);
					BufferedWriter yourFileBw = new BufferedWriter(yourFileFw);
					yourFileBw.write(string);
					yourFileBw.flush();
					yourFileBw.close();
				} catch (IOException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
				answerArea.setEditable(false);
				timeProgressBar.stop();
				
				//将对错情况写入到文件里
				//先删除文件
				File gradeFile = new File("file/Grade.txt");
                if (gradeFile.exists()) {
                    gradeFile.delete();
                }
              //定义答案文件和答题文件的输入流
                File answersFile = new File("file/Answers.txt");
                FileReader answersRd;
				try {
					answersRd = new FileReader(answersFile);
					BufferedReader answersBufferRd = new BufferedReader(answersRd);
					FileReader yourFileRd = new FileReader(yourFile);
					BufferedReader yourFileBufferRd = new BufferedReader(yourFileRd);
					String thisLineAnswer = "";
	                String yourAnswer = "";
	                List<Integer> error = new ArrayList<Integer>();
	                List<Integer> right = new ArrayList<Integer>();
	                int num = 1;
	                while ((thisLineAnswer = answersBufferRd.readLine()) != null) {
	                    yourAnswer = yourFileBufferRd.readLine();
	                    if (yourAnswer.equals(thisLineAnswer)) {
	                        right.add(num);
	                    } else {
	                        error.add(num);
	                    }
	                    num++;
	                }
	                answersBufferRd.close();
	                yourFileBufferRd.close();
	              //将答题结果写入到Grade文件中
	                FileWriter gradeFw = new FileWriter(gradeFile, true);
	                BufferedWriter gradeBw = new BufferedWriter(gradeFw);
	                gradeBw.write("Correct:"+right.size()+"(");
	                for (int x=0;x<right.size();x++){
	                    gradeBw.write(right.get(x)+",");
	                }
	                gradeBw.write(")");
	                gradeBw.newLine();
	                gradeBw.write("Wrong:"+error.size()+"(");
	                for (int y=0;y<error.size();y++){
	                    gradeBw.write(error.get(y)+",");
	                }
	                gradeBw.write(")");
	                gradeBw.newLine();
	                //关闭流
	                gradeBw.flush();
	                gradeBw.close();
				} catch (FileNotFoundException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				} catch (IOException e){
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
			}
		});
		
	}
	
	//主函数
	public static void main(String[] args) {
		// TODO Auto-generated method stub
		try {
			UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
		} catch (ClassNotFoundException | InstantiationException
				| IllegalAccessException | UnsupportedLookAndFeelException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		new MainFrame();
	}

}

  (2)进度条

package main;

import java.awt.Color;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JProgressBar;
import javax.swing.Timer;
import param.Param;

public class TimeProgressBar extends JProgressBar implements ActionListener{
	public int maxTime = Param.time;// 设置最大时间
	private Timer timer = new Timer(1000, this);// 计时器,int
												// delay一秒减少一次和ActionListener监听器
	public MainFrame mainFrame;

	public TimeProgressBar(MainFrame mainFrame) {
		this.mainFrame = mainFrame;
		// mouseEvent();
		this.setMaximum(maxTime);
		this.setValue(maxTime);
		this.setBackground(Color.gray);
		this.setStringPainted(true);// 设置 stringPainted
									// 属性的值,该属性确定进度条是否应该呈现进度字符串。
		this.setString(maxTime + "秒");
	}
	
	@Override
	public void actionPerformed(ActionEvent arg0) {
			// TODO Auto-generated method stub
			maxTime--;
			this.setValue(maxTime);
			this.setString(maxTime + "秒");
			
			//时间一到,计时停下来,不然会进入负数
			if(maxTime==0){
				this.stop();
				mainFrame.answerArea.setEditable(false);
			}
		
	}
	/**
	 * 开始
	 */
	public void start() {
		timer.start();
	}

	/**
	 * 暂停
	 */
	public void stop() {
		timer.stop();
	}
	/**
	 * 重新开始
	 */
	public void restart() {
		maxTime = Param.time;
		this.setMaximum(maxTime);// 重新设置JProgress的最大值
		this.setValue(maxTime);
		this.setString(maxTime + "秒");
		timer.start();
	}
}

  (3)式子类,包含式子生成和结果生成

package bean;

import java.util.ArrayList;
import java.util.List;
import java.util.Random;

/**
 * Created by Administrator on 2017/9/23.
 */
public class Formula {
    private List numberList = new ArrayList();//数列
    private List operatorList = new ArrayList();//算符列

    //空构造
    public Formula() {

    }

    //gei与set方法
    public List getNumberList() {
        return numberList;
    }

    public void setNumberList(List numberList) {
        this.numberList = numberList;
    }

    public List getOperatorList() {
        return operatorList;
    }

    public void setOperatorList(List operatorList) {
        this.operatorList = operatorList;
    }

    //带参构造,生成r自然数范围内的式子
    public Formula(Integer r) {
        //判断生成的式子有几个运算符
        Random random = new Random();
        Integer num = random.nextInt(3);
        StringBuffer formula = new StringBuffer("");
        //生成运算符为1个的式子
        if (num == 0) {
            Number number1 = new Number(r);
            this.numberList.add(number1);
            Operator operator1 = new Operator();
            this.operatorList.add(operator1.getOperator());
            Number number2 = new Number(r);
            this.numberList.add(number2);
        } else if (num == 1) {//生成运算符为2的式子
            Number number1 = new Number(r);
            this.numberList.add(number1);
            Operator operator1 = new Operator();
            this.operatorList.add(operator1.getOperator());
            Number number2 = new Number(r);
            this.numberList.add(number2);
            Operator operator2 = new Operator();
            this.operatorList.add(operator2.getOperator());
            Number number3 = new Number(r);
            this.numberList.add(number3);
        } else {//生成运算符为3的式子
            Number number1 = new Number(r);
            this.numberList.add(number1);
            Operator operator1 = new Operator();
            this.operatorList.add(operator1.getOperator());
            Number number2 = new Number(r);
            this.numberList.add(number2);
            Operator operator2 = new Operator();
            this.operatorList.add(operator2.getOperator());
            Number number3 = new Number(r);
            this.numberList.add(number3);
            Operator operator3 = new Operator();
            this.operatorList.add(operator3.getOperator());
            Number number4 = new Number(r);
            this.numberList.add(number4);
        }
    }

    //根据numberList和operatorList生成一个式子
    public String getAFormula() {
        StringBuffer stringBuffer = new StringBuffer("");
        stringBuffer.append(numberList.get(0));
        for (int i = 0; i < operatorList.size(); i++) {
            stringBuffer.append(operatorList.get(i));
            stringBuffer.append(numberList.get(i + 1));
        }
        return stringBuffer.toString();
    }

    //生成式子答案
    public Number getAnswser() {
        //先对式子的*和÷进行处理
        int i = 0;
        while (i < operatorList.size()) {
            //如果数列里的数个数是0,则返回该方法
            if (numberList.size()==1){
                return (Number) numberList.get(0);
            }
            //当算符出现*和÷的时候
            if (operatorList.get(i).equals("*") || operatorList.get(i).equals("÷")) {
                //取得运算符两侧的数
                Number numberFront = (Number) numberList.get(i);
                Number numberAfter = (Number) numberList.get(i + 1);
                //求得运算符两侧数值的分子部分
                int numberFrontMolecule = numberFront.getInteger() * numberFront.getDenominator() + numberFront.getMolecule();
                int numberAfterMolecule = numberAfter.getInteger() * numberAfter.getDenominator() + numberAfter.getMolecule();
                int endMolecule = 0;
                int endDenominator = 0;
                //算得两数相乘的分子值和分母值
                if (operatorList.get(i).equals("*")) {
                    endMolecule = numberFrontMolecule * numberAfterMolecule;
                    endDenominator = numberFront.getDenominator() * numberAfter.getDenominator();
                }
                if (operatorList.get(i).equals("÷")) {
                    endMolecule = numberFrontMolecule * numberAfter.getDenominator();
                    endDenominator = numberAfterMolecule * numberFront.getDenominator();
                }
                int endInteger = 0;//初始分子的整数部分为0
                if (endMolecule > endDenominator) {
                    endInteger = endMolecule / endDenominator;
                    endMolecule = endMolecule % endDenominator;
                }
                //求最大公约数
                int smaller = endMolecule > endDenominator ? endMolecule : endDenominator;
                int maxCommonFactor = 1;
                for (int j = 1; j <= smaller; j++) {
                    if (endMolecule % j == 0 && endDenominator % j == 0) {
                        maxCommonFactor = j;
                    }
                }
                endMolecule = endMolecule / maxCommonFactor;
                endDenominator = endDenominator / maxCommonFactor;
                Number endNumber = new Number(endInteger, endMolecule, endDenominator);//约分后的式子
                this.numberList.add(i, endNumber);
                this.numberList.remove(i + 1);
                this.numberList.remove(i + 1);
                this.operatorList.remove(i);
            }else {
                i++;
            }
        }

        //进行完*÷处理后进行+-处理
        while (operatorList.size()!=0){
            //取得运算符两侧的数
            Number numberFront = (Number) numberList.get(0);
            Number numberAfter = (Number) numberList.get(1);
            //求得运算符两侧数值的分子部分
            int numberFrontMolecule = numberFront.getInteger() * numberFront.getDenominator() + numberFront.getMolecule();
            int numberAfterMolecule = numberAfter.getInteger() * numberAfter.getDenominator() + numberAfter.getMolecule();
            //不管两式子的分母一样或不一样,都把两分母相乘
            int endDenominator=numberFront.getDenominator()*numberAfter.getDenominator();
            //如果为+符,就进行+算
            int allMolecule1=numberFrontMolecule*numberAfter.getDenominator();
            int allMolecule2=numberAfterMolecule*numberFront.getDenominator();
            int endMolecule=0;//定义未约分前的分子部分
            if (operatorList.get(0).equals("+")){
                endMolecule=allMolecule1+allMolecule2;
            }
            if (operatorList.get(0).equals("-")){
                endMolecule=allMolecule1-allMolecule2;
            }
            int endInteger = 0;//初始分子的整数部分为0
            if (endMolecule > endDenominator) {
                endInteger = endMolecule / endDenominator;
                endMolecule = endMolecule % endDenominator;
            }
            //求最大公约数
            int smaller = endMolecule > endDenominator ? endMolecule : endDenominator;
            int maxCommonFactor = 1;
            for (int j = 1; j <= smaller; j++) {
                if (endMolecule % j == 0 && endDenominator % j == 0) {
                    maxCommonFactor = j;
                }
            }
            endMolecule = endMolecule / maxCommonFactor;
            endDenominator = endDenominator / maxCommonFactor;
            Number endNumber = new Number(endInteger, endMolecule, endDenominator);//约分后的式子
            this.numberList.add(0, endNumber);
            this.numberList.remove(1);
            this.numberList.remove(1);
            this.operatorList.remove(0);
        }
        return (Number) numberList.get(0);
    }
}

  (4)菜单类,包含按键监听

package menu;

import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.HashSet;
import java.util.Set;

import javax.swing.ButtonGroup;
import javax.swing.JCheckBoxMenuItem;
import javax.swing.JMenu;
import javax.swing.JMenuBar;
import javax.swing.JMenuItem;

import param.Param;
import main.MainFrame;

public class MainMenuBar extends JMenuBar {
	MainFrame mainFrame;
	JMenu menuSet = new JMenu(Param.set);// 设置按钮
	JMenuItem menuHistory = new JMenuItem(Param.history);// 查看历史情况
	JMenuItem paramSet = new JMenuItem(Param.paramSet);// 参数设置
	JMenuItem timeSet = new JMenuItem(Param.timeSet);// 时间设置
	JMenu languageSet = new JMenu(Param.languageSet);// 语言设置

	public MainMenuBar(MainFrame mainFrame) {
		this.mainFrame = mainFrame;
		init();
		mouseEvent();
	}

	// 初始化
	public void init() {
		menuSet.add(paramSet);
		menuSet.add(timeSet);
		menuSet.add(languageSet);
		menuSet.add(menuHistory);

		this.add(menuSet);
	}

	public void mouseEvent() {
		//历史成绩按钮
		menuHistory.addActionListener(new ActionListener(){

			@Override
			public void actionPerformed(ActionEvent arg0) {
				// TODO Auto-generated method stub
				new History(mainFrame);
			}
			
		});
		//参数设置
		paramSet.addActionListener(new ActionListener() {

			@Override
			public void actionPerformed(ActionEvent arg0) {
				// TODO Auto-generated method stub
				new ParamSet(mainFrame);
			}

		});

		//时间设置
		timeSet.addActionListener(new ActionListener() {

			@Override
			public void actionPerformed(ActionEvent arg0) {
				// TODO Auto-generated method stub
				new TimeParamSet(mainFrame);
			}

		});

		//语言设置
		ButtonGroup languageGroup = new ButtonGroup();
		Set<String> lgSet = new HashSet<String>();
		languageSet.add(Param.chinese);
		languageSet.add(Param.english);
		for (String str : lgSet) {
			final JCheckBoxMenuItem checkBoxMenuItem = new JCheckBoxMenuItem(
					str);
			languageGroup.add(checkBoxMenuItem);
			languageSet.add(checkBoxMenuItem);
			if (str.equals("中文") || str.equals("chinese")) {
				checkBoxMenuItem.setSelected(true);
				checkBoxMenuItem.addActionListener(new ActionListener() {

					@Override
					public void actionPerformed(ActionEvent arg0) {
						// TODO Auto-generated method stub
						Param.exNumber = "生成题目数";
						Param.exRange = "数字范围";
						Param.timeConfig = "时间设置(秒)";
						Param.determine = "确定";
						Param.remaind = "请输入正整数";
						Param.title = "四则运算器";
						Param.generatingItem = "生成题目";
						Param.begin = "开始";
						Param.submit = "提交答案";
						Param.set = "设置";
						Param.history = "历史情况";
						Param.timeSet = "时间设置";
						Param.paramSet = "参数设置";
						Param.languageSet = "语言设置";
						Param.chinese = "中文";
						Param.english = "英文";
						mainFrame.repaint();
					}

				});
			} else {
				checkBoxMenuItem.setSelected(true);
				checkBoxMenuItem.addActionListener(new ActionListener() {

					@Override
					public void actionPerformed(ActionEvent arg0) {
						// TODO Auto-generated method stub
						Param.exNumber = "Number of items";
						Param.exRange = "range";
						Param.timeConfig = "TimeSet(s)";
						Param.determine = "determine";
						Param.remaind = "Please enter a positive integer";
						Param.title = "四则运算器";
						Param.generatingItem = "generating Item";
						Param.begin = "begin";
						Param.submit = "submit";
						Param.set = "Set";
						Param.history = "History";
						Param.timeSet = "TimeSet";
						Param.paramSet = "ParamSet";
						Param.languageSet = "LanguageSet";
						Param.chinese = "Chinese";
						Param.english = "English";
						mainFrame.repaint();
					}

				});
			}
		}

	}

}

  

4.程序运行:

主界面:                               参数设置:

题目生成:                              开始做题,计时开始,并且让答题区变为可编辑:

提交答案,答题区继续变为不可编辑,进度条停止            查看结果:

5.小结感受:

  我感觉这次结对编程,真正的发挥了1+1>2的情况,首先是时间上,使用git可以做到进度一起推进的情况,划分好模块,可以两头一起推进,剩下了不少

时间。再者是思路,两个人的思路总是比一个人的思路多很多,思考问题容易进入死角,得到别人的提醒尤为重要。

  感觉这次结对编程,首先是要熟悉git的使用,在git上花了很多的时间,然后是出现代码冲突的情况,两个人要在一块找冲突的地方在哪,以前也组队一起

做过项目,同时做到最后合代码时合得眼花缭乱,使用git感觉可以方便许多,然后是GUI编程,有一段时间不用了,感觉现在用起来又生疏了许多,有些细节

也没有去细细扣,比如说答题出现暂停的情况。

6.评价搭档

  首先,我的搭档和我一样,有着学习的冲劲和动力,经常在深夜也能够一起思考讨论问题。

  再者,我的搭档做得不足的地方,我觉得做得都很好,能够提出有建设性的意见和建议,也能够在没思路的时候指出思路,但是感觉平时白天能做完的事

尽量别拖到晚上,影响睡眠也挺影响第二天的状态。

  最后,我感觉我和搭档能够把界面做得更好看一些,可以加一些背景图片之类的。

7.照片摆拍

8.PSP

 

 

posted @ 2017-10-22 21:29  呼呼龙  阅读(175)  评论(3编辑  收藏  举报