目的:当屏幕上出现不同的图像时,通过按键盘上的空格键来测试一个人的反应能力。
常规:允许参与者输入姓名和年龄。记录我和日期。
要求:启动时,点击屏幕右侧显示的绿色按钮,程序运行时使该变为红色,然后在屏幕中间显示4x4cm的红色正方形1秒。接下来显示一个4x4x4x4蓝色三角形,持续80毫秒。然后再次显示正方形1秒。每一次显示一个三角形,这个人点击键盘,程序就会记录下发生这种情况的次数。以不规则的方式交替显示正方形和三角形。例如:先显示正方形,再显示三角形,然后显示正方形两次,在正方形和三角形之间的20毫秒内不显示任何内容。记住,当人们看到三角形并按下键盘上的空格键时,要记下时间。运行此程序6分钟,然后显示最终计数。
本次小测使用GUI图形化界面实现,内部数据没有连接数据库,因此为一次性数据。每次测量数据无法保存。
首先在程序一开始,想采用面向面向过程的方法,但是由于学艺不精,有一些结构上的混乱。代码仅供参考,希望可以提出建议。
在程序一开始先大致判断需要用到的面板,按钮组件,在最上面定义好,后期有需要再添加别的组件。
JFrame jf=new JFrame("反应时间测试");
JLabel label = new JLabel("出现三角形图形时候摁下空格");
JLabel label1 = new JLabel(); //用来展示图片
ImageIcon icon0 = new ImageIcon("src\\picture\\红色正方形.png");//正方形图标组件
ImageIcon icon1 = new ImageIcon("src\\picture\\蓝色三角形2.png");//三角形图标组件
JButton jButton ;
JButton jButton1;
int jishu = 1;
int jishu1= 2;
int zhuangtai = 1;
ArrayList<Date> list = new ArrayList<>();
然后定义与方法名相同的Interface()方法,此方法自启动。
public Interface(){
this.init();
this.addAction();
}
定义init()方法,用来设置各个按钮的参数,以及面板的组装。其中各个按钮的位置需要自己一点一点的调试,达到自己满意的位置。
其中在最后一个按钮添加时候遇到点问题,一添加按钮,会把整个界面全部占满。后期找了很多参考代码没有解决,在一次运行时候,代码自己好了,不明白原理。就很神奇,我称之为神学<😂>。
private void init(){
// jf.setLayout(new BorderLayout());
jf.setSize(600,500); //设置窗体大小
GUITools.center(jf); //设置居中
label1.setBounds(220, 120, 150,150);
jf.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
//设置标签格式
label.setFont(new Font("幼圆", Font.BOLD, 16));
label.setBounds(200, 30, 250, 40);
//设置图片格式
Image book0 = icon0.getImage();
book0 = book0.getScaledInstance(150,150,Image.SCALE_DEFAULT);
icon0.setImage(book0);
//label1.setIcon(icon0);
Image book1 = icon1.getImage();
book1 = book1.getScaledInstance(300,150,Image.SCALE_DEFAULT);
icon1.setImage(book1);
JPanel panel = new JPanel();
// panel.setBorder(new TitledBorder(null, "\u4E66\u7C4D\u6DFB\u52A0", TitledBorder.LEADING, TitledBorder.TOP, null, Color.RED));
panel.setBounds(500, 500, 200, 300);
jf.getContentPane().add(panel);
panel.setLayout(null);
jButton = new JButton("开始");
jButton.setFont(new Font("幼圆", Font.BOLD, 14));
jButton.setBounds(480, 350, 77, 27);
jButton.setBackground(Color.green);
panel.add(jButton);
jf.add(label);
jf.add(label1);
jf.add(panel);
jf.setVisible(true);
}
接下来定义一个改变中间图形的方法,前期我写代码的时候发现,面板中的组件,从一开始创建好之后,就不能再进行添加,删除以及更改,但是组件的内容可以更换,因此定义中间JLabel类型的标签后期可以替换显示的照片来达到更换照片的目的。
//改变中间图形
private class label1_change extends Thread{
int i;
public void run(){
while (true){
Random ra = new Random();
i = ra.nextInt(2);
zhuangtai=i; //把现在显示的照片传递出去
if (i==1){
++jishu1;
label1.setIcon(icon1);//蓝色三角形,持续80ms
try {
TimeUnit.MILLISECONDS.sleep(80);
} catch (InterruptedException e) {
e.printStackTrace();
}
}else {
label1.setIcon(icon0);//红色正方形,持续1s
try {
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
//程序运行完,等待20ms
try {
TimeUnit.MILLISECONDS.sleep(20);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
创建一个定时器用来纪录运行了多长时间,达到运行一定时长截至程序运行的目的。
我在寻找代码的过程中找到两种关于计时器的程序,一种是等待一定时间后,执行一段代码固定时间,多次执行;第二种是等待一定时间,程序只运行一次。
接下来是第一种。
定义一个addAction()方法,用来设置监听事件。其中包括对开始,结束的监听;对整个界面的键盘事件监听,按下回车纪录次数。
第一种方法虽然我最终没有使用,但是纪录下来,以后或许能够用到
//设置计时器
private class MyThread extends Thread{
/* @Override
public void run() {
//创建定时器截止程序运行
TimerTask task = new TimerTask() {
@Override
public void run() {
//执行条件
jf.dispose();
new Interface();
*//* String format = new DecimalFormat("0.00%").format((double) (jishu) / (double) (jishu1));
//增强for循环,把操作成功的时间纪录遍历一遍
for (Date s :list){
System.out.println(s);
}
System.out.println("您的反应为:");*//*
}
};
Timer timer = new Timer();
//定义等待时间,
long delay =5*1000;
//定义每次执行时间10s
long intecalperiod = 1;
//安排任务在一段时间内执行
timer.scheduleAtFixedRate(task,delay,intecalperiod);//等待delay时间后,执行intecalperiod时间的是task程序
}
}*/
接下来是第二种,也就是我使用的那一种
//设置计时器
private class MyThread extends Thread{
@Override
public void run() {
Timer timer = new Timer();
timer.schedule(new TimerTask() {
@Override
public void run() {
jf.dispose();
new Interface();
String format = new DecimalFormat("0.00%").format((double) (jishu) / (double) (jishu1));
//增强for循环,把操作成功的时间纪录遍历一遍
for (Date s :list){
System.out.println(s);
}
System.out.println("您的反应为:"+format);
}
},30*1000);//设置时间为30秒
}
}
最后,对按钮,空格添加监听事件
//设置监听事件
private void addAction(){
//设置开始按钮
jButton.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
if (jButton.getBackground()==Color.green){
MyThread myThread = new MyThread(); //创建Mythread的实例化对象
myThread.start();//开启线程
jButton.setText("结束");
jButton.setBackground(Color.red);//设置为红色
new label1_change().start(); //运行更换图案的方法
}else {
jButton.setText("开始");
jButton.setBackground(Color.green);
jf.dispose();
new Interface();
String format = new DecimalFormat("0.00%").format((double) (jishu) / (double) (jishu1));
//增强for循环,把操作成功的时间纪录遍历一遍
for (Date s :list){
System.out.println(s);
}
System.out.println("您的反应为:"+format);
}
}
});
//设置键盘监听
jButton1.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
if (jButton.getBackground() == Color.red && zhuangtai == 1) {
jishu++;
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd hh-mm-ss");
String time = null;
time = sdf.format(new Date());//纪录当下时间
list.add(time);//把当前纪录存进数组
}
}});
其中用到的GUITools类,我在使用定义这个中间方法的时候,有导入一个包
import java.awt.*;
如果没有这个包的话,建议直接设置图形的位置。调用setBounds()方法设置大小以及坐标。
public class GUITools {
public static void center(Component c) {
Toolkit kit = Toolkit.getDefaultToolkit();
int x = (kit.getScreenSize().width - c.getWidth()) / 2;
int y = (kit.getScreenSize().height - c.getHeight()) / 2;
c.setLocation(x, y);
}
}
然后定义一个主方法来调用这个函数,这个结构学会后,真的挺方便的,对于代码后期的运行以及维护有很大的便利,结构清晰,能够一眼看出以及找到需要修改的部门。目前本人能看的懂,自己写,有些四不像的感觉,正在向那个方向靠拢,见谅。
public class main {
public static void main(String[] args) {
new Interface();
}
}
最后,这是运行结果。运行程序出现以下界面,因为没有点击开始运行,所以中间部分图形没有显示。
点击开始运行后,红方块和绿三角随机显示,只有三角的时候摁下空格才会被纪录到。
最后当运行到系统设置的时间之后,结束程序。并且返回运行的纪录。例如:运行过程中什么时刻点击过空格的纪录。以及反应速度(小于1大于0,数据越大,反应代表越快)。