打字训练测试系统
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
第一章打字训练测试系统的概述 (2)
1.1 系统总体设计概述 (2)
1.2 系统功能需求分析 (2)
第二章系统设计的主要类和方法 (3)
2.1 API类和系统主类: (3)
2.2 图形界面设计 (3)
2.3 创建线程 (4)
2.4 文件管理 (5)
2.5 事件监听响应 (5)
第三章系统功能设计 (5)
3.1 主窗口界面设计 (5)
3.2 添加文件功能实现 (9)
3.3 设置测试时间设计 (12)
3.4 速度和剩余时间设计 (14)
3.5 显示测试结果 (15)
第四章总结 (16)
第一章打字训练测试系统的概述
1.1 系统总体设计概述
计算机在20世纪后半期取得了飞速发展,随着网络的发展,已经成为人们日常生活中不可或缺的一部分,如何快速的掌握计算机操作技能显得非常重要,其中打字速度更是衡量一个人操作熟练与否的重要标志,因此开发一种高效的打字程序显得迫在眉睫。
目前大多数打字程序都是只能在Windows下运行,跨平台运行能力不是很强。
为了适应当下的需求,格外需要一款新的打字程序。
我们小组开发的这个用JA V A设计的打字训练测试软件,它的主要功能是从文件中录入一段英文或中文文档,并能给出错误率和平均录入速度。
在该文档设计中,为了方便,文档格式设置为txt格式。
该软件能实现从磁盘上寻找打开一个文件、实时显示打字速度和剩余时间等功能,应用到GUI,多线程,文件的输入输出等知识。
需要从磁盘打开要录入文件的样本,录入时需要实时显示录入速度和剩余时间,录入结束后,显示录入速度和错误率。
录入结束方式可以通过点击“结束测试”按钮结束测试,文章录入完成也自动结束录入,到达设置时间也自动结束录入。
最后要求图形界面,界面良好美观,主要是为了锻炼一下打字技能,提高打字速度,并能给出错误分析。
本系统构建学生打字练习系统,基于所开发的打字程序界面友好,图形复杂。
打字练习程序中应用到eclipse最新版本,java1.6以上版本的jdk。
对于打字测试进入整体的部署。
完成打字练习程序开发,培养程序设计和开发能力。
1.2 系统功能需求分析
要求设计一款打字训练测试程序,实现从磁盘上寻找打开一个文件、设置打字时间、时实显示打字速度和剩余时间等功能,应用到GUI,多线程,文件的输入输出等知识。
需要从磁盘打开要录入文件的样本,录入前可以设定录入练习时间,录入时需要实时显示录入速度和剩余时间,录入结束后,显示录入速度和错误率。
录入结束方式可以通过点击“结束测试”按钮结束测试,文章录入完成也自动结束录入,到达设置时间也自动结束录入。
最后要求图形界面,界面良好美观。
根据任务要求主要遇到的问题在于如何很好的监听按键菜单事件,监听部分键盘;如何在打开文件对话框中过滤只显示txt和目录文件,读取文件后如何一部一部地显示并能正确统计录入字数和错误字数;如何在录入文章时,同时监控系统时间,并能尽量减少cpu占用。
经过对现有一般打字程序的使用者的调查与分析,得出若要编写此打字程序,本程序必需主要实现的功能如下:
1)添加文件。
从磁盘添加现有的文本文件显示在程序界面上方。
2)设置测试时间。
在打字开始前,可以设置测试时间,方便快捷地结束测试。
3)显示测试结果。
结果主要包括:打字速度和错误率。
4)在录入过程中,显示当前速度和剩余时间。
为了实时提醒用户打字速度和打字时间可以
实时提示打字速度和剩余时间(剩余时间是设置的测试时间减掉已使用的时间).
5)使用菜单栏。
要求菜单栏可以从“文件——>打开”添加文件,可以从“文件——>退出”
退出程序,可以从“帮助——>关于”了解程序信息。
6)多情况结束测试。
1.当测试结束时,结束测试。
2.当点击“结束测试”按钮结束测试。
3.当文章录入完成结束测试。
主要功能图如图1.1所示
打字训练功能模块
文件功能
退出系统测试功能
打开文件
取
消
操
作
时
间
设
置
速
度
测
试
显
示
错
误
率图1.1 打字训练功能模块
第二章系统设计的主要类和方法
2.1 API类和系统主类
该软件采用JA V A语言编写,运用myeclipse开发环境,程序整体采用一个Typer 主类和用一个TyperProgram类完成图形界面的编写和监听响应事件。
当程序运行时调用TyperProgram类,启动线程。
import java.io.*;
import java.awt.event.*;
import javax.swing.*;
import javax.swing.event.*;
import javax.swing.filechooser.FileFilter;
public class Typer{
public static void main(String[] args){
TyperProgram tp=new TyperProgram();
tp.start();
}
2.2 图形界面设计
定义setWindow()方法来设计用户界面,整体的JFrame用BorderLayout进行布局分成北中南三个块。
其中北边是一个用GridLayout布局的JPanel分成1行2列,两列中分别是一
个JTextField;中间是一个GridLayout布局的JPanel分成2行1列;南边是一个FlowLayout 布局的JPanel,里面放两个居中的按钮。
public void setWindow(){
JFrame jf_title=new JFrame("打字训练测试软件");//创建标题窗口
Container cont=jf_title.getContentPane();
cont.setLayout(new BorderLayout());
Font font=new Font("黑体",Font.PLAIN,17);
Font font_text=new Font("times new man",Font.PLAIN,18);
//设置字体大小
JMenuBar jmb=new JMenuBar();//创建菜单条
JMenu jm_file,jm_help;//创建文件和帮助两个菜单
jm_file=new JMenu("文件");jm_file.setFont(font);
jm_help=new JMenu("帮助");jm_help.setFont(font);
.......}
2.3 创建线程
在设计本系统时,由于同时存在多个执行单元,如打字素的显示,打字错误率计算以及剩余时间的统计,它们必须按照不同的执行方式共同工作,所以为了让程序活的更高的性能,提高程序的响应速度及程序的数据吞吐量,我们采用了多线程控制,即首先定义一个主线程TyperProgram ,然后再在这个主线程内部定义一个子线程Timer,监听键盘和文本输入用匿名内部类来实现,TyperProgram和Timer用多线程来实现并发运行。
当程序运行时TyperProgram的对象先运行,当点击开始按钮时Timer对象开始运行。
A.创建主线程
class TyperProgram extends Thread implements ActionListener { JPanel jpc1,jpc2,jpg,jp_button,jpb;
JMenuItem jmi_open,jmi_exit,jmi_about;
JTextField jtf_pace,jtf_time;
JTextArea jta_text,jta_type;
JButton jbt_add,jbt_start,jbt_end;
CardLayout card1,card2;
String state="",strTime="";
StringBuffer strbFile;
int words,errorWords;
double startTime;
File getPath;//获得文件路径
BufferedReader buf; //定义字符输入流
boolean fileOver,lock=true;
………………}
B.创建子线程
用Timer类实现Runnable接口从而实现对系统时间监控显示完成录入后的成绩计算。
其中监听键盘和文本输入用匿名内部类来实现。
putScore()用来结束测试后,统计错误率,并将错误率显示在界面,右上方的JTextField中。
private class Timer implements Runnable{
public void putScore(){…}//定义计算错误率方法
public void errcolor(){…}//定义错别字设置显色方法
public void run(){…}//重写run方法
………………}
2.4 文件管理
添加打开文件用打开对话框,通过定义readFile函数来获取文件路径,再使用addFile方法及文件过滤器来添加txt文件进行测。
public void readFile(){…}//读取文件
public void addFile(){…}//添加文件
2.5 事件监听响应
我们用setListener()来设置多种监听,如事件监听,键盘监听,文本监听等。
其中事件监听由于实现了接口ActionListener,直接添加本类,再于函数actionPerformed()来实现,而其它监听都用的是匿名内部类来实现。
很成功地完成了多种监听处理功能。
public boolean isDigit(String str){…}//确定指定位置为字符
public void setstart(){…}//设置测试时间
public void setListener(){…}//设置监听
public void actionPerformed(ActionEvent e){…}//事件监听接口
public void run(){…
}
第三章系统功能设计
3.1 主窗口界面设计
窗口为一个添加菜单栏的JFrame,菜单栏包括主要有文件和帮助两个部分,整体的JFrame用BorderLayout进行布局分成北中南三个块。
其中北边是一个用GridLayout布局的JPanel分成0行2列,两列分别是一个JTextField(当前的速度,剩余时间);中间是一个GridLayout布局的JPanel分成2行1列,每行分别为一个CardLayout布局的JPanel,其中第一行里放了一个带按钮的JPanel(添加文件)和一个JTextArea,第二行为JTextArea;南边是一个FlowLayout布局的JPanel,里面放两个居中的按钮(开始测试,结束测试),相关代码如下,该界面如图2.4.1所示
public void setWindow(){
JFrame jf=new JFrame("打字训练测试软件");//创建标题窗口
Container con=jf.getContentPane(); //声明一个Container对象
con.setLayout(new BorderLayout());//设置容器的布局方式为
BorderLayout
Font font=new Font("黑体",Font.PLAIN,17);//设置字体大小
Font font_text=new Font("times new man",Font.PLAIN,18);
JMenuBar jmb=new JMenuBar();//创建菜单条
JMenu jm_file,jm_help;//创建文件和帮助两个菜单并设置字体
jm_file=new JMenu("文件");jm_file.setFont(font);
jm_help=new JMenu("帮助");jm_help.setFont(font);
//创建打开,退出,关于三个菜单项并设置相关热键
jmi_open=new JMenuItem("打开
");jmi_open.setFont(font);jmi_open.setActionCommand("打开");
jmi_open.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_O,Inpu tEvent.CTRL_MASK));
jmi_exit= new JMenuItem("退出
");jmi_exit.setFont(font);jmi_exit.setActionCommand("退出");
jmi_exit.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_E,Inpu tEvent.CTRL_MASK));
jmi_about=new JMenuItem("关于
");jmi_about.setFont(font);jmi_about.setActionCommand("关于");
jm_file.add(jmi_open);//在文件菜单上添加打开菜单项
jm_file.addSeparator();//菜单项之间的分界线
jm_file.add(jmi_exit);//在文件菜单添加退出菜单项
jm_help.add(jmi_about);//在帮助菜单上添加关于菜单项
jmb.add(jm_file);jmb.add(jm_help);//在菜单条上添加文件和帮助两个菜单
jtf_pace=new JTextField();//创建一行显示速度的文本
jtf_pace.setFont(font);
jtf_pace.setEditable(false);//使显示速度的文本无法编辑
jtf_time=new JTextField();//创建一行显示时间的文本
jtf_time.setFont(font);
jtf_time.setEditable(false);//使显示时间的文本无法编辑
JPanel jp_show=new JPanel(new GridLayout(1,2));//创建一个显示结果的测试栏,并将其布局设置为1行两列
jp_show.add(jtf_pace);jp_show.add(jtf_time);//添加速度和时间到该测试栏
con.add(BorderLayout.NORTH,jp_show);//将测试栏置于北面
jpg=new JPanel();
jpg.setLayout(new GridLayout(2,1));//创建GridLayout的布局方式为2行,1列
jta_text=new JTextArea();//创建显示多行的添加文本
jta_type=new JTextArea();//创建显示多行的输入文本
jta_text.setFont(font_text); //设置文字字体
jta_text.setLineWrap(true);//设置为自动换行
jta_text.setEditable(false);//使添加的文字无法编辑
jta_text.setBackground(new Color(200,255,200));//设置添加文字背景色
jta_type.setFont(font_text);///设置输入文本的字体
jta_type.setLineWrap(true);
jta_type.setBackground(new Color(200,200,255));//设置输入文字背景色
jbt_add=new JButton("添加文件");jbt_add.setFont(font);//
jbt_add.setActionCommand("打开");//设置jbt_add按钮的激发事件
jpb=new JPanel(new CardLayout());//创建卡片布局
card1=new CardLayout();
jpc1=new JPanel(card1);
jpc1.add("card1",jpb);jpc1.add("card2",jta_text);
JLabel jb=new JLabel(new ImageIcon("image/keybord.png"));//创建一个图片标签
card2=new CardLayout();
jpc2=new JPanel(card2);
jpc2.add("card1",jb);
jpc2.add("card2",jta_type);
jpg.add(jpc1);
jpg.add(jpc2);
con.add(BorderLayout.CENTER,jpg);
jp_button=new JPanel();
jp_button.setLayout(new FlowLayout(FlowLayout.CENTER,50,0));//设置该JPanel为流布局,使放置的组件居中,行高为50个单位
jbt_start=new JButton("开始测试");
jbt_start.setFont(font);jbt_start.setActionCommand("开始");
jbt_end=new JButton("结束测试");
jbt_end.setFont(font);jbt_end.setActionCommand("结束");//设置
jbt_end按钮的激发事件
jp_button.add(jbt_start);
jp_button.add(jbt_end);//将该两个按钮添加到
con.add(BorderLayout.SOUTH,jp_button);//将该面板设置为南面
jf.setBounds(250,100,710,705);//设置整个界面的大小
jf.setJMenuBar(jmb);
jf.setVisible(true);
jbt_add.requestFocus();
jf.setResizable(false);//设置窗体不可编辑
jf.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
}
public void actionPerformed(ActionEvent e){
String strAction=e.getActionCommand();
if(strAction=="打开"&&lock){
addFile();
}
else if(strAction=="退出"){
System.exit(1);
}
else if(strAction=="关于"){
String str=" 版权所有 2012";
JOptionPane.showMessageDialog(null,str,"关于
",JOptionPane.PLAIN_MESSAGE);
}
else if(strAction=="开始"&&lock){
if(!state.equals("addFile"))
JOptionPane.showMessageDialog(null,"你还没有添加有效文档","提示",RMATION_MESSAGE);
else
setstart();
}
else if(strAction=="结束"){
if(!state.equals("start"))
JOptionPane.showMessageDialog(null,"你还没有测试","提示",RMATION_MESSAGE);
else
state="over";
}
}
图3.1 起始界面设计
3.2 添加文件功能实现
添加打开文件用打开对话框,并对对话框添加文件过滤器,代码如下,界面如图2.4.2所示public void readyFile(){
String strFile="";
FileReader in=null;
try{
String strLine="";
in=new FileReader(getPath);
buf=new BufferedReader(in);
strLine=buf.readLine();
while(strLine!=null){
strFile+=strLine;
strLine=buf.readLine();
}
}catch(IOException e1){
e1.printStackTrace();
}
strbFile=new StringBuffer(strFile);
fileOver=false;
}
public void readFile(){
String strPart=""; int n=320;
if(strbFile.length()<=n){
jta_text.setText(strbFile+"\n");
fileOver=true;
return;
}
strPart=strbFile.substring(0,n);
strbFile=strbFile.delete(0,n);
jta_text.setText(strPart+"\n");
}
public void addFile(){//增加文件的方法
JFileChooser fileCh=new JFileChooser();
fileCh.setCurrentDirectory(new File("files"));
fileCh.setFileFilter(new FileFilter(){
public boolean accept(File f){
return
f.getName().toLowerCase().endsWith(".txt")||f.isDirectory();
}
public String getDescription(){
return"文本文档 *.txt*";
}
});
if(fileCh.showOpenDialog(null)==JFileChooser.CANCEL_OPTION)return ;
getPath=fileCh.getSelectedFile();
if(!getPath.getPath().toLowerCase().endsWith(".txt")){ JOptionPane.showMessageDialog(null,"请选择文本文档","提示
",RMATION_MESSAGE);
return;
}
readyFile();
readFile();
state="addFile";
card1.show(jpc1,"card2");
jbt_add.requestFocus();
}
图 3.2添加文件界面设计
3.3 设置测试时间设计
录入时间设定用一个对话框实现,并接收输入信息,默认录入测试时间为5分钟,主要代码如下该界面如图2.4.3所示
public void setstart(){
JPanel jp=new JPanel(new GridLayout(2,0));
JLabel jlab=new JLabel("设置测试时间(分):");
JTextField jtfTime=new JTextField();
jtfTime.setText("5");
jp.add(jlab);jp.add(jtfTime);
int select=JOptionPane.showConfirmDialog(null,jp,"设置
",JOptionPane.OK_CANCEL_OPTION,JOptionPane.PLAIN_MESSAGE);
if(select!=JOptionPane.OK_OPTION)return;
strTime=jtfTime.getText();
if(isDigit(strTime)){
if(jta_text.getText()!=null){
readyFile();
readFile();
}
card2.show(jpc2,"card2");
jta_type.setText(null);
jta_type.setEditable(true);
jta_type.requestFocus();
state="start";
lock=false;
startTime=System.currentTimeMillis();
Timer ti=new Timer();
Thread t=new Thread(ti);
t.start();
}
else{
JOptionPane.showMessageDialog(null,"请输入数字","提示
",RMATION_MESSAGE);
}
}
public void setListener(){//设置监听
jmi_open.addActionListener(this);
jmi_exit.addActionListener(this);
jmi_about.addActionListener(this);
jbt_add.addActionListener(this);
jbt_start.addActionListener(this);
jbt_end.addActionListener(this);
jbt_add.addKeyListener(new KeyListener(){
public void keyPressed(KeyEvent e1){
if(e1.getKeyCode()==KeyEvent.VK_ENTER)
addFile();
}
public void keyReleased(KeyEvent e2){}
public void keyTyped(KeyEvent e2){}
});
jta_type.getDocument().addDocumentListener(new
DocumentListener(){
public void insertUpdate(DocumentEvent e1){
String str1=jta_text.getText();
String str2=jta_type.getText();
if(str1.length()==str2.length()&&str2.endsWith("\n")){
if(fileOver){
state="over";
}
else{
words+=str2.length();
for(int i=0;i<str2.length();i++)
if(str1.charAt(i)!=str2.charAt(i))
errorWords++;
EventQueue.invokeLater(new Runnable(){
public void run() {
jta_type.setText(null);
}
});
readFile();
}
}
}
public void changedUpdate(DocumentEvent e2){}
public void removeUpdate(DocumentEvent e3){}
});
}
图2.4.3 设置测试时间
3.4 速度和剩余时间设计
实时显示录入速度和剩余时间通过实现Runnable接口的一个Timer类来计算实现。
当开始录入时获取一个系统时间startTime=System.currentTimeMillis(),然后每隔一秒获取一个系统时间nowTime=System.currentTimeMillis(),同时统计当前录入的字数count=jta2.getText().length(),字数除以用两个时间之差得到速度最后单位换算为(字/分);剩余时间等于设置时间减去花费的时间remainTime=setTime-spendTime最后转换为分和秒,代码如下。
public void putScore(){
jta_type.setEditable(false);//设置添加文本不可编辑
String str1,str2;//定义两个字符串,分别为从添加文本和输入文本中获取的字符
str1=jta_text.getText();str2=jta_type.getText();
double error; //定义错误率
int
k=str1.length()<str2.length()?str2.length()-str1.length():0,
l=str1.length()<str2.length()?str1.length():str2.length();
for(int i=0;i<l;i++)
if(str1.charAt(i)!=str2.charAt(i))//若两个字符串在同一索引处的字符不相同,
k++;
error=(words+l)==0?0:((errorWords+k)*1.0/(words+l))*100;
jtf_time.setText("错误率:"+Math.ceil(error*100)/100.0+"%");
errorWords=0;words=0;
state="addFile";lock=true;
jbt_start.requestFocus();
}
public void run(){
double nowTime,spendTime,setTime,speed=0,remainTime;
int count,remainMin,remainSec;
nowTime=System.currentTimeMillis();
spendTime=(nowTime-startTime)/60000;
setTime=Double.parseDouble(strTime);
while(spendTime<setTime&&!state.equals("over")){
count=jta_type.getText().length();
speed=(words+count)/spendTime;
remainTime=setTime-spendTime;
remainMin=(int)remainTime;
remainSec=(int)Math.round((remainTime-remainMin)*60);
jtf_pace.setText("当前的速度:"+Math.round(speed)+"字/分");
jtf_time.setText("剩余时间:"+remainMin+"分"+remainSec+"秒");
try{
Thread.sleep(1000);
}catch(Exception e){
e.printStackTrace();
}
nowTime=System.currentTimeMillis();
spendTime=(nowTime-startTime)/60000;
}
jtf_pace.setText("速度:"+Math.round(speed)+"字/分");
putScore();
}
3.5 显示测试结果
显示录入速度和错误率。
录入速度计算同上,错误率等于总的错字数/录入总字数error=(words+l)==0?0:((errorWords+k)*1.0/(words+l))*100(注:如果没有录入就结束测试,错误率为0%),界面如图2.4.5所示
图3.5 显示测试结果
第四章总结
经过几个星期,我们的课程设计总算完成了,这其中虽然遇到不少问题,通过询问同学,老师的帮助也一一解决了,通过这次课程设计,使大家的编程能力都提高了不少,这次课程设计给大家提供了一个动手,思考和解决问题的机会,巩固了所学的课程。
在设计中,大家难免会遇到多种分歧,比如在布局管理器上就要想到怎样放置整个组件,使整个界面美观,简单,如金义善同学就想到了在起始界面上添加一张键盘图片使空白处不至于那么空洞,不过由于时间仓促,没有再进一步完善,图片上其实可以设置类似的按键来同步键入的字符,周攀同学设计的速度和时间设置上的算法很周到,陈小琳同学在添加文件上的算法设计
也显示其扎实的编程能力,其中考虑到如何过滤非txt格式的文档。
本人在他们设计的基础之上也进行了相关完善,总之,这次课程设计是由大家一起完成的,本人也体会到了团队合
作的氛围,哪方面不懂的大家都可以一起解决,分享自己的编程心得,最终达到学习的目的。
小组分工。