前言:鄙人是大二在读学生,大二上学期Java课程设计选了一个秒表计时器的题目,在此把代码和心得分享出来(懒人可以直接看PPT)。鄙人资历尚浅,代码中会有许多不当之处,望各位大佬海涵,有更好的建议希望各位大佬留言评论区。
题目要求
设计一个与手机秒表类似的计时器,以钟表图形的方式呈现。
- 当用户用鼠标单击界面的“开始”按钮或图标时,秒表开始计时,表及数字都自动发生变化;当用户再次点击按钮,秒表暂停计时,按钮字样变为“继续”;当用户用鼠标点击“继续”按钮,秒表继续计时。
- 界面上还有一个“复位”按钮,当未点击“开始”按钮,没有进入计时状态时,“复位”按钮为灰色不可选,当开始计时后,“复位”按钮变为可选状态,当用户点击复位按钮时,秒表计时清零。
设计思路
- 首先利用java中的swing创建窗口,及其相关的组件,构造出大概的图像,如下图
- 然后利用java中的计时器类(Timer),让指针随着时间转动(本来有视频演示的,但是奈何视频鄙人还不会插入……)
- 接着声明一些变量(例如haveStart,isStop,number)来帮助判断秒表的状态(如下图)
- 结合静态变量,给三个按钮添加事件监听(jp_*为第*个按钮)
//手动换行分开三个按钮(手动滑稽)
//手动换行分开三个按钮(手动滑稽)
- 使用jdbc技术连接java程序和mysql数据库(这个题目里面是没有要求的,但是想着完美一点就加上去了,下面3张图为代码演示和结果演示)
//手动换行分开图片(手动滑稽)
//手动换行分开图片(手动滑稽),下面这张图是数据库存储后的结果,为了方便展示直接使用了数据库管理系统的可视化工具navicat
程序分析
程序能够符合题目的所有要求,并且结合实际考虑,在题目要求之外添加了如下几个功能:
- 在未点击开始按钮时,暂停按钮也设置成灰色不可点击的状态
- 在未点击开始前,点击暂停或者复位按钮的话,会有弹窗提醒,告诉使用者“程序未开始,此按钮不可选!”
- 在窗口右侧添加了多行文本域,可以展示在一次使用中的多次记录的次序和时长
- 使用了JDBC技术连接了java程序和mysql数据库,可以在点击复位按钮时自动把每次记录的次序,时长,记录的时间存入数据库中,便于数据的保存和查询。
程序的不足之处:
- 因为采用了Java Swing中的组件来构造钟表,所以钟表图形简陋,窗口上的单行文本域和多行文本域也显得有些呆滞
心得与体会
在这个课程设计中遇到的难题及其解决方案:
1. 导包错误
这个课程设计中使用到了java中的计时器类(Timer),但是由于之前没有接触过这个类,所以是通过一些视频,及百度才知道了这个类,使用这个类是需要导包的,但是不止一个包含有这个类,当时我下意识的导了java.swing这个包,因为这个课程设计很多都用到了swing,导致程序报错(见下图),但是明明我和百度和视频上的几乎一模一样,在漫长的折磨下,我才想到可能是导错包了。
解决方案:在java的API文档和百度搜索上比较详细的了解了这个类在不同包下的使用之后,挑选了一个比较合适的包导入,并且修改java语句,尝试完成自己让指针转动的需求
2.版本不匹配问题
我在电脑上配置的mysql的版本是5.7.36,然后用到的jdbc的jar是最新的8.0.27版本的,所以在起初看视频学习jdbc技术时,敲着一模一样的代码,但是我这里会报错(见下图),这就让人十分苦恼,难以继续学习下去
解决方案:在官网上找到对应版本的jdbc的jar文件(即5.7.36版本的jdbc的jar文件),然后把这个文件配置到运行环境中
几个有用的网址:
1. Overview - Java 11中文版 - API参考文档
Java中文在线帮助文档
2.https://mvnrepository.com/artifact/mysql/mysqlconnector-java
可以很容易获取Jdbc中任意版本的jar包
3. 百度一下,你就知道
可以解答我们目前为止在编程上遇到的90%的问题
源码
package Miaobiao;
import javax.swing.*;
import java.awt.event.*;
import java.sql.*;
import java.text.SimpleDateFormat;
import java.awt.*;
import java.util.*;
import java.util.Date;
import java.util.Timer;
public class MiaoBiao {
//获得记录的时间
SimpleDateFormat formatter= new SimpleDateFormat("yyyy-MM-dd 'at' HH:mm:ss ");
Date date = new Date(System.currentTimeMillis());
String s;
// 创造各个组件
final static double pai = 3.14159;
JFrame jf = new JFrame("秒表窗口");
JPanel jp_one = new JPanel();
JPanel jp_two = new JPanel();
JPanel jp_three = new JPanel();
static int location_x = 0;
static int location_y = 110;
static MyCanvas myCanvas = new MyCanvas();
JButton jb_one = new JButton("开始");
JButton jb_two = new JButton("暂停");
JButton jb_three = new JButton("复位");
// 未开始时点击复位弹出的对话框
JDialog jd = new JDialog(jf, true);
JTextArea jta = new JTextArea("程序未开始,此按钮不可选!");
static JTextField tf = new JTextField(10);
JTextArea ta = new JTextArea(30, 10);
// 设置一个变量来观察秒表是否暂停
static boolean isStop = true;
// 设置一个变量记录时间
static private int t = 0;
// 设置一个变量是否开始
static boolean haveStart = false;
// 设置一个变量记录秒表运行次数
static int number = 0;
private static class MyTimer extends TimerTask {
@Override
public void run() {
if (isStop) {
} else {
//更新指针终点的x,y坐标,并且更新单行文本域的内容
t++;
location_x = (int) (Math.cos((pai / 2 - t * pai / 30)) * 110);
location_y = (int) (Math.sin((pai / 2 - t * pai / 30)) * 110);
tf.setText("" + t + "秒");
myCanvas.repaint();
}
// TODO Auto-generated method stub
}
}
/* void Jdbc() throws SQLException
{
Driver driver =new com.mysql.jdbc.Driver();
String url="jdbc:mysql://localhost:3306/miaobiao";
Properties info =new Properties();
info.setProperty("user", "root");
info.setProperty("password", "root");
Connection conn=driver.connect(url, info);
String sql="insert into record(number,time,date) values(?,?,?)";
PreparedStatement ps=conn.prepareStatement(sql);
ps.setInt(1, number);
ps.setString(2, t+"秒");
ps.setString(3,s);
ps.execute();
ps.close();
conn.close();
}*/
// 组装函数
public void init() {
// 设置弹窗内容
jd.setBounds(300, 300, 300, 200);
jd.setTitle("错误!");
jd.add(jta);
// jd.setTe
// 给复位按钮设置成灰色
jb_two.setBackground(Color.gray);
jb_three.setBackground(Color.gray);
// 给按钮添加事件监听
jb_one.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
if (jb_two.getActionCommand().equals("暂停")) {
isStop = false;
haveStart = true;
jb_two.setBackground(new Color(236, 242, 248));
jb_three.setBackground(new Color(236, 242, 248));
}
}
});
jb_two.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
// 判断这个按钮当前的状态
if (!haveStart && e.getActionCommand().equals("暂停")) {
jd.setVisible(true);
} else if (haveStart && e.getActionCommand().equals("暂停")) {
isStop = true;
jb_two.setText("继续");
} else {
isStop = false;
jb_two.setText("暂停");
}
}
});
jb_three.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
if (haveStart) {
// 更新成员变量的属性值
isStop = true;
haveStart = false;
location_x = 0;
location_y = 110;
jb_two.setText("暂停");
// 在右边的文本域中更新内容
ta.append("第" + (++number )+ "次:" + t + "秒" + "\n");
//写入数据库
/* try {
date = new Date(System.currentTimeMillis());
s=formatter.format(date);
Jdbc();
} catch (SQLException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}*/
t = 0;
tf.setText("");
// 给两个按钮回复颜色
jb_three.setBackground(Color.gray);
jb_two.setBackground(Color.gray);
myCanvas.repaint();
} else {
jd.setVisible(true);
}
}
});
// 给三个面板添加组件
myCanvas.setSize(new Dimension(360, 360));
//myCanvas.setBackground(Color.blue);
jp_one.add(myCanvas);
jp_one.add(tf);
jp_two.add(jb_one);
jp_two.add(jb_two);
jp_two.add(jb_three);
jp_three.add(ta);
// 给窗口添加三个面板
jf.add(jp_one, BorderLayout.CENTER);
jf.add(jp_two, BorderLayout.SOUTH);
jf.add(jp_three, BorderLayout.EAST);
// 设置窗口位置,大小,可见性,添加窗口关闭监听
jf.setBounds(200, 200, 500, 500);
jf.setVisible(true);
//jf.addWindowListener(new MyListener());
jf.setDefaultCloseOperation(1);
Timer timer = new Timer();
timer.schedule(new MyTimer(), 0, 1000);
}
public static void main(String[] args) {
new MiaoBiao().init();
}
// 创建画布
private static class MyCanvas extends Canvas {
@Override
public void paint(Graphics g) {
// 绘制钟表图
g.drawOval(60, 40, 250, 250);
g.setFont((new Font("Times", Font.BOLD, 30)));
g.drawString("12", 170, 65);
g.drawString("3", 290, 175);
g.drawString("6", 178, 288);
g.drawString("9", 62, 175);
g.drawString("1", 235, 80);
g.drawString("2", 275, 120);
g.drawString("4", 275, 235);
g.drawString("5", 235, 275);
g.drawString("7", 126, 275);
g.drawString("8", 80, 235);
g.drawString("10", 75, 120);
g.drawString("11", 115, 80);
// 绘制指针,利用计时器更新 a b 的值使指针不停的转动
int a = 185 + location_x;
int b = 165 - location_y;
g.drawLine(185, 165, a, b);
}
}
}
注:为了让代码能够成功运行,有关数据库部分的代码被注释了。(注释掉的部分:第67-83行,第133-140行)
另附本人的实验报告文档与分享会的PPT:
链接:https://pan.baidu.com/s/17FUTWmdxrha2Lpy8aARPyQ
提取码:zlry
好了~第一篇博客到此就结束了,大家对这个课程设计有什么问题可以在评论区留言~也欢迎各位大佬提出宝贵的修改意见~