标准化考试系统

1、主类Test

package cn.kong;

import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.WindowEvent;
import java.awt.event.WindowListener;
//主类
public class Test extends JFrame {
    TestArea testPanel = null;
    Container con = null; //所有GUI的直接父类
    public Test(){
        super("标准化模拟考试");
        testPanel = new TestArea();//文本域
        con = getContentPane();//获取面板内容
        con.add(testPanel,BorderLayout.CENTER);//面板添加到窗口中间
        this.setDefaultCloseOperation(JFrame.DO_NOTHING_ON_CLOSE); //关闭窗口操作,不让其关闭
        //窗口监听机制
        addWindowListener(new WindowListener() {
            public void windowOpened(WindowEvent e) {}
            public void windowClosing(WindowEvent e) {
                //设置窗口格式
                JDialog 弹出窗口 = new JDialog(Test.this,true);
                弹出窗口.setTitle("离开考试");
                JLabel 标签 = new JLabel("同学,你确定退出考试吗?",JLabel.CENTER);
                标签.setFont(new Font("宋体",Font.BOLD,14));
                标签.setForeground(Color.red);
                弹出窗口.add(标签,BorderLayout.CENTER);

                //新建面板
                JPanel j1 = new JPanel();
                //创建按钮
                final JButton 退出 = new JButton("退出");
                final JButton 取消 = new JButton("取消");
                退出.setForeground(Color.blue);
                取消.setForeground(Color.blue);
                //将按钮加入面板
                j1.add(退出);
                j1.add(取消);
                弹出窗口.add(j1,BorderLayout.SOUTH);

                //为退出按钮添加监听器
                退出.addActionListener(new ActionListener() {
                    @Override
                    public void actionPerformed(ActionEvent e) {
                        System.exit(0);
                    }
                });

                //创建取消按钮监听器
                取消.addActionListener(new ActionListener() {
                    @Override
                    public void actionPerformed(ActionEvent e) {
                        弹出窗口.dispose();
                    }
                });

                //为窗口添加组件
                弹出窗口.setSize(300,200);
                弹出窗口.setLocation(800,400);
                弹出窗口.setVisible(true);
                弹出窗口.setForeground(Color.BLUE);
            }
            public void windowClosed(WindowEvent e) {}//一下的东西都重写,虽然用不到
            public void windowIconified(WindowEvent e) {}
            public void windowDeiconified(WindowEvent e) {}
            public void windowActivated(WindowEvent e) {}
            public void windowDeactivated(WindowEvent e) { }
        });
        setVisible(true);//面板可视
        setBounds(250,150,1200,800);//面板大小
        con.validate();//验证此容器及其所有子组件。使用 validate 方法会使容器再次布置其子组件。
        validate();//默认为this.validate()
    }
    public static void main(String[] args) {
        new Test();
    }
}


2、ReadTestQuestion类

package cn.kong;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
import java.util.StringTokenizer;

public class ReadTestQuestion {
    String filename="";//存放考题文件名的字符串
    String correctAnswer = "";//存放正确答案的字符串
    String testContent = "";//试题内容
    String selection = "";//用户提交的答案
    int score = 0; //用户的分数
    long time = 0; //试题用时
    boolean 完成考试 = false;
    File f = null;//获取文件目录或这文件名
    FileReader in = null;//文件字符输入流
    BufferedReader 读取 = null; //字符缓冲流

    //设置试题文件名方法
    public void setFilename(String name){
        filename = name;
        score = 0;
        selection="";
        try{
            if(in != null && 读取 != null ){//刚开始这两个文件不能有内容
                in.close();
                读取.close();
            }
            f = new File(filename); //创建文件对象
            in = new FileReader(f);//创建字符流对象
            读取 = new BufferedReader(in);//创建缓冲流对象
            correctAnswer = (读取.readLine()).trim();//String trim()返回一个字符串,并删除任何前导和尾随空格
            String temp = (读取.readLine()).trim();
            StringTokenizer token = new StringTokenizer(temp,":");//以分号分割时间
            int hour = Integer.parseInt(token.nextToken());//分隔好的时间,完成自动装箱和拆箱过程
            int minute = Integer.parseInt(token.nextToken());
            int second = Integer.parseInt(token.nextToken());
            time = 1000*(second+minute*60+hour*60*60);//获取时间的毫秒表示
        }catch(Exception e){
            testContent="没有选则试题";
        }
    }

    //得到文件名方法
    public String getFilename(){
        return filename;
    }
    //得到时间的方法
    public long getTime(){ return time; }
    //设置是否完成考试方法
    public void set完成考试(boolean b){ 完成考试 = b; }
    //得到是否完成考试的布尔值
    public boolean get完成考试(){ return 完成考试; }
    //得到试题内容
    public String getTestContent(){
        try{
            String s = null;
            StringBuffer temp = new StringBuffer();
            if(读取!= null){
                while((s = 读取.readLine()) != null){
                    if(s.startsWith("**")) //判断试题开始标志
                        break;
                    temp.append("\n"+s);
                    if(s.startsWith("endend")){//判断结束的标志
                        in.close();
                        读取.close();
                        完成考试=true;
                    }
                }
                testContent = new String(temp);
            }else{
                testContent = new String("没有选则试题");
            }
        }catch(Exception e){
            testContent = "试题内容为空,考试结束!!";
        }
        return testContent; //返回考试内容
    }

    //设置考生答案方法
    public void setSelection(String s){
        selection = selection + s;
    }

    //得到成绩的方法
    public int getScore(){
        score = 0;
        int length1 = selection.length();//读取考生答案长度
        int length2 = correctAnswer.length();//获取正确答案长度
        int min = Math.min(length1,length2);//获取答案长度最小值
        for(int i = 0 ; i < min; i++){
            try{
                if(selection.charAt(i) == correctAnswer.charAt(i)){//看两个字符串下标对应的字符是否一样来判断得多少分
                    score++;
                }
            }catch(StringIndexOutOfBoundsException e){
                i = 0;
            }
        }
        return score;
    }

    //得到考生信息方法
    public String getMessages(){
        int length1 = selection.length();
        int length2 = correctAnswer.length();
        int length = Math.min(length1,length2);
        String message = "正确答案:"+correctAnswer.substring(0,length)+"\n"+"你的回答:"+selection+"\n";
        return message;
    }
}


3、TestArea类

package cn.kong;

import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.ItemEvent;
import java.awt.event.ItemListener;
import java.io.File;
import java.io.*;

class FileName implements FilenameFilter{ //获取文件名类
    String str = null;
    public FileName(String s){ //获取文件名后缀
        str = "."+s;
    }
    public boolean accept(File dir, String name){ //判断文件名是否以刚才的后缀名结尾的,从而判断文件类型
        return name.endsWith(str);
    }
}

//定义主面板类
public class TestArea extends JPanel implements ActionListener, ItemListener,Runnable {
    //继承的三个接口都要实现

    Choice list = null; //下拉式弹出菜单选项

    JTextArea 试题显示区 = null,消息区 = null; //文本域组件(多行接受)

    JRadioButton box[]; //复选框按钮

    JButton 提交该题答案,读取下一题,查看分数; //用到按钮

    ReadTestQuestion 读取试题 = null;
    JLabel welcomeLabel = null;//显示文本标签组件

    Thread countTime = null; //用来倒计时
    long time = 0;
    boolean 是否关闭计时器 = false;
    boolean 是否暂停计时 = false;
    JTextField timeShow = null; //文本框(单行展示)用来存放事件
    JButton 暂停或继续计时 = null;
    int flag = 0, flag1 = 0;

    public TestArea(){

        list = new Choice();
        list.add("Please choice examination");
        String 当前目录 = System.getProperty("user.dir");//用此方法来获得当前所在的目录
        //System.out.println(当前目录);
        File dir = new File(当前目录); //获取当前目录
        FileName fileText = new FileName("txt"); //写出试题的后缀名
        String fileName[] = dir.list(fileText);//把当前目录下的所有以.txt结尾的文件名放到fileName[]中
        for(int i = 0; i < fileName.length;i++){//把文件名放到list弹出菜单中,制成弹出式菜单
            list.add(fileName[i]);
        }

        试题显示区 = new JTextArea(15,12);//行和列
        试题显示区.setLineWrap(true);//获取文本区域的换行政策。
        试题显示区.setWrapStyleWord(true);//如果文本区域是包装线,则设置使用的包装样式
        试题显示区.setFont(new Font("TimesRoman",Font.PLAIN,20));
        试题显示区.setForeground(Color.BLUE);
        试题显示区.setEditable(false);


        消息区 = new JTextArea(8,8);
        消息区.setForeground(Color.blue);
        消息区.setLineWrap(true);//换行政策
        消息区.setWrapStyleWord(true);//包装样式
        消息区.setEditable(false);
        消息区.setFont(new Font("TimesRoman",Font.PLAIN,20));
        ButtonGroup group = new ButtonGroup();


        countTime = new Thread(this);
        String s[] = {"A","B","C","D"};
        box = new JRadioButton[4];
        for(int i = 0; i < 4; i++){ //设置复选框按钮的名称
            box[i] = new JRadioButton(s[i]);
            group.add(box[i]);
        }

        暂停或继续计时 = new JButton("暂停计时");
        暂停或继续计时.addActionListener(this);// 增填监听机制
        提交该题答案 = new JButton("提交该题答案");
        读取下一题 = new JButton("读取第一题");//首先为读取第一题
        读取下一题.setForeground(Color.blue);

        提交该题答案.setForeground(Color.blue);
        查看分数 = new JButton("查看分数");
        查看分数.setForeground(Color.blue);
        提交该题答案.setEnabled(false);//设置当前控件是否被激活,是否可用。

        提交该题答案.addActionListener(this);//复选框类的监听机制
        读取下一题.addActionListener(this);//一定要知道两个类不同动作监听机制的区别
        查看分数.addActionListener(this);
        list.addItemListener(this);//菜单类的动作监听机制

        读取试题 = new ReadTestQuestion();
        JPanel pAddbox = new JPanel() ;//面板组件

        for(int i = 0;i < 4; i++){
            pAddbox.add(box[i]); //往面板中增加复选框按钮
        }
        //对于此面板不适用FlowBorder布局管理器,使用Box类的BoxLayout布局管理器

        Box boxH1 = Box.createVerticalBox();//创建一个 Box显示其组件的Box,固定组件的数量空间
        Box boxH2 = Box.createVerticalBox();
        Box baseBox = Box.createHorizontalBox();//需要组件空间的固定数量空间
        boxH1.add(new JLabel("选择试题文件"));
        boxH1.add(list);
        boxH1.add(new JScrollPane(消息区));
        boxH1.add(查看分数);
        timeShow = new JTextField(20);
        timeShow.setHorizontalAlignment(SwingConstants.RIGHT);//设置文本的水平对齐方式
        timeShow.setEditable(false);//不可编辑

        JPanel p1 = new JPanel();
        p1.add(new JLabel("剩余时间"));
        p1.add(timeShow);
        p1.add(暂停或继续计时);
        boxH1.add(p1);//讲以上组件都固定到boxH1上

        boxH2.add(new JLabel("试题内容:"));
        boxH2.add(new JScrollPane(试题显示区));
        JPanel p2 = new JPanel();
        p2.add(pAddbox);
        p2.add(提交该题答案);
        p2.add(读取下一题);
        boxH2.add(p2);//以上组件都固定到boxH2上

        baseBox.add(boxH1);
        baseBox.add(boxH2);//再将boxH1和boxH2都固定到baseBos上作为一个整体

        setLayout(new BorderLayout());//边界布局管理器
        add(baseBox,BorderLayout.CENTER);//将标签和baseBox都放到布局管理器中
        welcomeLabel = new JLabel("欢迎来到考试系统,祝大家考试顺利",JLabel.CENTER);//设置标签
        welcomeLabel.setFont((new Font("隶书",Font.PLAIN,24)));
        welcomeLabel.setForeground(Color.blue);
        add(welcomeLabel,BorderLayout.NORTH);
    }
    public void itemStateChanged(ItemEvent e) {//改变列表框中得选中项得动作监听机制
        timeShow.setText(null);
        是否关闭计时器 = false;//计时器的三种状态
        是否暂停计时 = false;
        暂停或继续计时.setText("暂停计时");
        String name = (String)list.getSelectedItem();//获取弹出式下拉菜单的试卷名称
        读取试题.setFilename(name);
        读取试题.set完成考试(false);
        time = 读取试题.getTime();//答题事件

        if(countTime.isAlive()){ //测试时间线程是否还活着
            是否关闭计时器 = true;
            countTime.interrupt();//强行中断线程
        }
        countTime = new Thread(this);//重新创建线程

        消息区.setText(null);
        试题显示区.setText(null);
        读取下一题.setText("读取第一题");
        提交该题答案.setEnabled(false);
        读取下一题.setEnabled(true); //刚开始的时候,只有读取第一题可以编辑或单机,其它按钮都不能动
        welcomeLabel.setText("欢迎考试,你选择的试题是:"+读取试题.getFilename());

    }

    public void actionPerformed(ActionEvent e) { //单机或双击复选框按钮的动作监听机制

        if(e.getSource() == 读取下一题){ //如果动作是读取下一题
            读取下一题.setText("读取下一题");
            提交该题答案.setEnabled(true);//这些按钮都可以编辑了
            String contentTest = 读取试题.getTestContent();
            试题显示区.setText(contentTest);//把试题内容放到文本域当中
            消息区.setText(null);
            读取下一题.setEnabled(false);//只要提交该题答案可以编辑了,读取下一题按钮就不可以编辑
            try{
                countTime.start();//倒计时开始(线程)
            }catch(Exception event){
                event.printStackTrace();
            }
        }

        if(e.getSource() == 提交该题答案){//动作是提交该题答案
            读取下一题.setEnabled(true);//此时读取下一题按钮可编辑
            提交该题答案.setEnabled(false);//但是提交该题答案按钮不可以编辑
            String answer = "?";
            for(int i = 0; i < 4; i++){
                if(box[i].isSelected()){
                    answer = box[i].getText();
                    box[i].setSelected(false);
                    break;
                }
            }
            读取试题.setSelection(answer);//获取答题者选项
        }

        if(e.getSource() == 查看分数){
            if(flag == 1|| flag1 == 1){
                int score = 读取试题.getScore();
                String messages = 读取试题.getMessages();
                消息区.setText("分数:"+score+"\n"+messages);
            }else{
                消息区.setText("对不起,你还没有答完题,不能查看分数");
            }

        }

        if(e.getSource()==暂停或继续计时){
            if(是否暂停计时 == false){ //没暂停的话
                暂停或继续计时.setText("继续计时");
                是否暂停计时=true;//为下次暂停做准备
            }else if(是否暂停计时 == true){
                暂停或继续计时.setText("暂停计时");
                是否暂停计时= false;//为下次不暂停做准备
                countTime.interrupt();//暂停计时的话,就必须中断线程
            }
        }
    }

    public synchronized void run() {//线程同步机制来解决线程安全问题
        while(true){
            if(time <= 0){//考试时间结束
                是否关闭计时器 = true;
                countTime.interrupt();
                提交该题答案.setEnabled(false);
                读取下一题.setEnabled(false);//一切答题按钮都不可用
                timeShow.setText("用时尽,考试结束");
                flag = 1;
            }else if(读取试题.get完成考试()){ //时间没用尽,并答题结束
                是否关闭计时器=true;
                timeShow.setText("考试效果:分数*剩余时间(秒)="+1.0*读取试题.getScore()*(time/1000));//显示剩余时间
                countTime.interrupt();//中断线程
                提交该题答案.setEnabled(false);
                读取下一题.setEnabled(false);//一切答题按钮都不可用
                flag1 = 1;
            }else if(time >= 1){ //还有时间,也没答完题的话,显示剩余的时间
                time = time - 1000;
                long leftTime = time/1000;
                long leftHour = leftTime/3600;
                long leftMinute = (leftTime - leftHour*3600)/60;
                long leftSecond = leftTime % 60;
                timeShow.setText(""+leftHour+"小时"+leftMinute+"分钟"+leftSecond+"秒");

            }
            try{
                Thread.sleep(1000); //线程休眠1s
            } catch (InterruptedException e) {
                if(是否关闭计时器 == true){
                    return;
                }
            }

            while(是否暂停计时 == true){ //生产者和消费者模式,保证只有暂停或不暂停两种状态
                try{
                    提交该题答案.setEnabled(false);
                    读取下一题.setEnabled(false);
                    wait();//唤醒线程
                }catch(InterruptedException e){
                    if(是否暂停计时 == false){
                        提交该题答案.setEnabled(true);
                        读取下一题.setEnabled(true);
                        notify();//休眠线程
                    }
                }
            }
        }
    }

}


评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值