结对编程
结对号数:
许晓烽: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

浙公网安备 33010602011771号