秒表
源码上传:https://github.com/data1213/-
1、UI设计:
2、代码:
Qtime、Qtimer类
需求:每隔1ms,更新显示,怎么通知计时周期到:
QTimer类帮助文档:
1 QTimer *timer = new QTimer(this); 2 connect(timer, SIGNAL(timeout()), this, SLOT(update())); 3 timer->start(1000); //1s
怎么获取时间数据:QTime帮助文档:
1 QTime 定义一个对象,它可以记录时间,并且可以人为指定时间,还有addMSecs方法可以实现增加指定毫秒,从而达到计数。
1 Example: 2 3 QTime n(14, 0, 0); // n == 14:00:00 4 QTime t; 5 t = n.addSecs(70); // t == 14:01:10 6 t = n.addSecs(-70); // t == 13:58:50 7 t = n.addSecs(10 * 60 * 60 + 5); // t == 00:00:05 8 t = n.addSecs(-15 * 60 * 60); // t == 23:00:00 9 10 See also addMSecs(), secsTo(), and QDateTime::addSecs().
通过toString方法可以获取一个QString类型的时间字符串:
1 QString QTime::toString(const QString &format) const 2 3 4 Format ---> Result 5 hh:mm:ss.zzz 14:13:09.042 6 h:m:s ap 2:13:9 pm 7 H:m:s a 14:13:9 pm
怎么显示到QLCDNumber控件:QLCDNumber帮助文档:
1 [slot] void QLCDNumber::display(const QString &s) 2 Displays the number represented by the string s.
这里的display方法是一个槽函数,这就是说明,槽函数可以像普通函数一样被调用,而不一定非要绑定信号才能调用。
1 #ifndef MAINWINDOW_H 2 #define MAINWINDOW_H 3 4 #include <QMainWindow> 5 #include <QTime> 6 #include <QTimer> 7 8 namespace Ui { 9 class MainWindow; 10 } 11 12 class MainWindow : public QMainWindow 13 { 14 Q_OBJECT 15 16 public: 17 explicit MainWindow(QWidget *parent = nullptr); 18 ~MainWindow(); 19 20 21 private slots: 22 void update_my_timer(); 23 24 void on_btn_begin_clicked(); 25 26 private: 27 QTime count_time; //计数,用于更新定时器 28 QTimer* p_timer; //定时器 29 Ui::MainWindow *ui; 30 }; 31 32 #endif // MAINWINDOW_H
1 #include "mainwindow.h" 2 #include "ui_mainwindow.h" 3 #include <QDebug> 4 5 MainWindow::MainWindow(QWidget *parent) : 6 QMainWindow(parent), 7 ui(new Ui::MainWindow) 8 { 9 ui->setupUi(this); 10 this->p_timer = new QTimer(); 11 connect(this->p_timer, SIGNAL(timeout()), this, SLOT(update_my_timer())); //绑定定时器和槽函数 12 13 } 14 15 MainWindow::~MainWindow() 16 { 17 delete ui; 18 } 19 20 21 //计时周期到响应的槽函数 22 void MainWindow::update_my_timer(){ 23 //1、更新当前计数 24 this->count_time = this->count_time.addMSecs(1); //增加1ms 25 //2、控件显式更新 26 QString timev = this->count_time.toString("hh:mm:ss.zzz"); 27 qDebug()<<timev; 28 this->ui->lcdNumber->display(timev); 29 30 } 31 32 //点击开始按钮之后触发计时器开始计时 33 void MainWindow::on_btn_begin_clicked() 34 { 35 this->p_timer->start(1); //启动1ms周期的定时器开始计时 36 //0、清空计数 37 this->count_time.setHMS(0,0,0,0); 38 }
效果:
改进:这里在设置计数时,认为设定从00:00:00:00开始,并且1ms计时周期,较短,需要处理的函数调用较多,这样容易出现问题,比如:当前进程较多,count_timer的计数有可能没有计到数,这样显式出来的就是错误的。
改进的做法:利用系统时间之差,来作为计数,这样系统时间始终是正确的,显式的始终是正确的。
1 int QTime::msecsTo(const QTime &t) const //返回两个QTime之间的ms差 2 [static] QTime QTime::currentTime()
1 //计时周期到响应的槽函数 2 void MainWindow::update_my_timer(){ 3 //记录当前时间 4 QTime c_time = QTime::currentTime(); 5 int diff = this->count_time.msecsTo(c_time); 6 7 QTime temp; 8 temp.setHMS(0,0,0,0); 9 10 temp = temp.addMSecs(diff); 11 QString str = temp.toString("hh:mm:ss.zzz"); 12 this->ui->lcdNumber->display(str); 13 14 } 15 16 //点击开始按钮之后触发计时器开始计时 17 void MainWindow::on_btn_begin_clicked() 18 { 19 this->p_timer->start(1); //启动1ms周期的定时器开始计时 20 //0、记录当前时间 21 this->count_time = QTime::currentTime(); 22 }
功能完善以及按钮逻辑设定:
1 #ifndef MAINWINDOW_H 2 #define MAINWINDOW_H 3 4 #include <QMainWindow> 5 #include <QTime> 6 #include <QTimer> 7 8 namespace Ui { 9 class MainWindow; 10 } 11 12 class MainWindow : public QMainWindow 13 { 14 Q_OBJECT 15 16 public: 17 explicit MainWindow(QWidget *parent = nullptr); 18 ~MainWindow(); 19 20 21 private slots: 22 void update_my_timer(); 23 24 void on_btn_begin_clicked(); 25 26 void on_btn_end_clicked(); 27 28 void on_btn_hold_clicked(); 29 30 void on_btn_flag_clicked(); 31 32 private: 33 QTime count_time; //计数,用于更新定时器 34 QTimer* p_timer; //定时器 35 QString show_time; //用于打点记录 36 Ui::MainWindow *ui; 37 }; 38 39 #endif // MAINWINDOW_H
1 #include "mainwindow.h" 2 #include "ui_mainwindow.h" 3 #include <QDebug> 4 5 MainWindow::MainWindow(QWidget *parent) : 6 QMainWindow(parent), 7 ui(new Ui::MainWindow) 8 { 9 ui->setupUi(this); 10 this->p_timer = new QTimer(); 11 connect(this->p_timer, SIGNAL(timeout()), this, SLOT(update_my_timer())); //绑定定时器和槽函数 12 13 //一开始只设置开始按钮可用 14 this->ui->btn_hold->setEnabled(false); 15 this->ui->btn_flag->setEnabled(false); 16 this->ui->btn_end->setEnabled(false); 17 18 19 } 20 21 MainWindow::~MainWindow() 22 { 23 delete ui; 24 } 25 26 27 //计时周期到响应的槽函数 28 void MainWindow::update_my_timer(){ 29 //记录当前时间 30 QTime c_time = QTime::currentTime(); 31 int diff = this->count_time.msecsTo(c_time); 32 33 QTime temp; 34 temp.setHMS(0,0,0,0); 35 36 temp = temp.addMSecs(diff); 37 QString str = temp.toString("hh:mm:ss.zzz"); 38 this->ui->lcdNumber->display(str); 39 40 //为了实现打点记录,这里先获取下当前时间 41 this->show_time = str; 42 43 } 44 45 //点击开始按钮之后触发计时器开始计时 46 void MainWindow::on_btn_begin_clicked() 47 { 48 this->p_timer->start(1); //启动1ms周期的定时器开始计时 49 //0、记录当前时间 50 this->count_time = QTime::currentTime(); 51 52 //避免再次点击,需要设置开始按钮不可用 53 this->ui->btn_begin->setEnabled(false); 54 //其他按钮可用 55 this->ui->btn_hold->setEnabled(true); 56 this->ui->btn_flag->setEnabled(true); 57 this->ui->btn_end->setEnabled(true); 58 } 59 60 void MainWindow::on_btn_end_clicked() 61 { 62 if(this->ui->btn_end->text() == "停止"){ 63 this->p_timer->stop(); 64 this->ui->btn_end->setText("清零"); 65 66 this->ui->btn_hold->setEnabled(false); //暂停不可用,开始也还是不能用 67 68 //如果是点击暂停按钮之后(本身变成继续)点击停止,那么需要将暂停按钮重新设置为暂停 69 this->ui->btn_hold->setText("暂停"); 70 71 }else { //清零 72 this->ui->lcdNumber->display("00:00:00:000"); 73 this->ui->textBrowser->clear(); 74 this->ui->btn_end->setText("停止"); 75 76 this->ui->btn_begin->setEnabled(true); //开始按钮重新可用 77 //this->ui->btn_hold->setEnabled(false);//暂停继续不可用 78 this->ui->btn_flag->setEnabled(false); 79 this->ui->btn_end->setEnabled(false); 80 } 81 } 82 83 //暂停功能 84 void MainWindow::on_btn_hold_clicked() 85 { 86 //old_time需要时静态的,记录点击暂停时的时间,保留到下次调用该函数——点击继续时调用 87 static QTime old_time; 88 89 if(this->ui->btn_hold->text() == "暂停"){ 90 old_time = QTime::currentTime(); 91 this->p_timer->stop();//暂停计数,当系统时间一直在走,而count_timer没有变化了 92 this->ui->btn_hold->setText("继续"); 93 }else { 94 QTime new_time = QTime::currentTime(); 95 int mdiff = old_time.msecsTo(new_time); 96 //更新从上一次点击暂停到这次点击继续之间系统经过的时间,然后补偿给count_timer 97 this->count_time = this->count_time.addMSecs(mdiff); 98 //开启计时器 99 this->p_timer->start(1); 100 this->ui->btn_hold->setText("暂停"); 101 } 102 } 103 104 //打点功能: 105 void MainWindow::on_btn_flag_clicked() 106 { 107 //获取当前计数,并显式在text brower控件中显式 108 //this->ui->lcdNumber->value();是一个double值,不是时间值 109 //this->ui->textBrowser->setText()方法会覆盖之前的文本内容 110 this->ui->textBrowser->append(this->show_time); 111 }
效果演示:
内在的趣味,表面的繁琐