QT定时器类
定时器类的使用主要包括定时和启动两个步骤。要使用OTimer类,需要引用头文件:
#include <QTimer>
QTimer类常用的成员函数有
(1)void start(std::chrono::miliseconds msec):启动定时器,参数为定时时间(单位为毫秒),如:
QTimer myTimer; //定义一个定时器对象
myTimer.start(1000); //启动定时器,定时时间1000ms
(2)void stop():停止定时器。
(3)void setTimerType(Qt::TimerType type):设置定时器精度。
Qt提供了三种定时策略,分别为:
精确的定时(Qt::PreciseTimer,毫秒级精度)
粗略的定时(Qt::CoarseTimer,5%左右的定时误差)--默认
非常粗略的定时(Qt::VeryCoarseTimer,精度在1s左右)
(4)void singleShot(int msec, const QObject *receiver, const char*member):单次定时。
定时时间由参数msec指定,单位为ms。定时结束后会自动调用receiver的槽函数member。
定时结束,会自动发射信号timeout(),且OTimer类的信号只有timeout()。
UI界面控件
这里定时器主要的使用控件为LCD Number
定时器功能实现,主要是通过相应按键转到槽,调用定时器的几个函数,以下为部分代码,后续会有全部的代码展示。
void MainWindow::update()
{
m_ftime += 0.1;
ui ->lcdNumber->display(m_ftime);
}
void MainWindow::on_Timer_begin_clicked()
{
m_timer.start(100);
}
void MainWindow::on_Timer_stop_clicked()
{
m_timer.stop();
}
void MainWindow::on_pushButton_4_clicked()
{
m_ftime = 0;
ui ->lcdNumber->display(m_ftime);
}
事件与事件过滤器
事件是程序内部或外部产生的事情或某种动作的通称。Ot中常见事件包括鼠标事件、键盘事件、定时事件、上下文菜单事件、关闭事件、拖放事件、绘制事件等。
在Qt中,事件的类型在QEvent::Type中有着详细的定义。
系统可以捕获事件,然后根据事件的类型和来源进行处理。
有时开发者会希望拦截某个事件并进行处理,从而实现自定义的功能。
部分事件的解读:
QEvent::MouseButtonPress 鼠标按下时,触发该事件,对应的子类是 QMouseEvent
QEvent::MouseMove 鼠标移动时,触发该事件,对应的子类是 QMouseEvent
QEvent::MouseButtonRelease 鼠标释放时,触发该事件,对应的子类是 QMouseEvent
由于LCD Number控件没有clicked()信号,所以不能响应鼠标单击事件。如果想要实现单击LCDNumber控件暂停/启动计时、右击LCDNumber控件清零计时时间的功能,应该怎么办呢?
一种方法是用自定义类继承控件类,然后重写mousePressEvent事件的处理函数。
另一种方法是使用事件过滤器。
事件过滤器可以对控件的事件进行过滤和拦截,从而改变处理事件的方式。
事件过滤器的使用
(1)在目标对象上调用installEventFilter()函数注册事件过滤器。也可以使用removeEventFilter()函数删除已有的事件过滤器。
(2)向类中添加eventFilter()函数,并完成事件处理代码。
(3)确定事件的后续去向,即是否需要将事件传递给系统处理。如果在eventFilter()函数中返回false,那么事件将发送给系统。如果返回了true,那么该事件会被丢弃,后续的事件过滤器和系统都不能检测到这一事件。
时间过滤器要点:
1.首先需要在mainWindow主程序中安装事件过滤器
ui->lcdNumber->installEventFilter(this);
2.重定义eventFilter()函数(该函式是一个虚函数)
重写bool eventFilter(QObject *obj, QEvent *event),参数不可以改变,因为是虚函数。
bool MainWindow::eventFilter(QObject *obj,QEvent *event)
{
if(obj == ui ->lcdNumber)
{
if (event->type() == QEvent::MouseButtonPress)
{
QMouseEvent *event2 = static_cast<QMouseEvent *>(event);
if(event2 ->button() == Qt::LeftButton)
{
if(m_timer.isActive() == 1)
{
m_timer.stop();
}
else
{
m_timer.start(100);
}
}
else if(event2 ->button() == Qt::RightButton)
{
m_ftime = 0;
ui->lcdNumber->display(m_ftime);
}
}
}
return QObject::eventFilter(obj,event);
}
这里需要注意,一定要加上头文件因为缺少头文件,会导致static static_cast(event)函数发生错误。
#include <QEvent>
#include <QMouseEvent>
#include <QKeyEvent>
事件过滤器详解
void QObject::installEventFilter(QObject *filterObj)
bool eventFilter(QObject *obj, QEvent *event);
Qt的事件过滤由以上两个方法实现,首先安装一个事件过滤器,然后重写bool eventFilter(QObject *obj, QEvent *event)函数
filterObj表示事件筛选器对象,它接收发送到此QObject对象的所有事件。筛选器可以停止事件,也可以将事件转发给此QObject对象。事件过滤器filterObj通过它的eventFilter()函数接收并处理事件。
返回值:eventFilter()有返回值。
- 如果返回true,表示事件过滤,不会发送到对象本身。
- 如果返回false,表示事件未过滤,会通过event()方法将事件分发到对象。
- 返回给基类进行处理,例:return QObject::eventFilter(obj, event)。
事件过滤器注册后,发送到控件的事件首先到达eventFilter()函数,然后在到达最终的目的地。
源码示例:
mainwindow.h文件
#include <QTimer>
#include <QEvent>
#include <QMouseEvent>
QT_BEGIN_NAMESPACE
namespace Ui { class MainWindow; }
QT_END_NAMESPACE
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
MainWindow(QWidget *parent = nullptr);
~MainWindow();
private slots:
void update();
void on_Timer_begin_clicked();
void on_Timer_stop_clicked();
void on_pushButton_4_clicked();
private:
Ui::MainWindow *ui;
QTimer m_timer;
float m_ftime;
bool eventFilter(QObject *obj,QEvent *event);
};
#endif // MAINWINDOW_H
maindow.cpp
#include "mainwindow.h"
#include "ui_mainwindow.h"
MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent)
, ui(new Ui::MainWindow)
{
ui->setupUi(this);
connect(&m_timer,SIGNAL(timeout()),this,SLOT(update()));
m_timer.setTimerType(Qt::PreciseTimer); //修改定时器策略为精确的定时
m_ftime = 0;
ui->lcdNumber->installEventFilter(this);
}
MainWindow::~MainWindow()
{
delete ui;
}
void MainWindow::update()
{
m_ftime += 0.1;
ui ->lcdNumber->display(m_ftime);
}
void MainWindow::on_Timer_begin_clicked()
{
m_timer.start(100);
}
void MainWindow::on_Timer_stop_clicked()
{
m_timer.stop();
}
void MainWindow::on_pushButton_4_clicked()
{
m_ftime = 0;
ui ->lcdNumber->display(m_ftime);
}
bool MainWindow::eventFilter(QObject *obj,QEvent *event)
{
/* 这里使用的是lcdnumber控件,不支持键盘输入,QLineEdit控件支持键盘输入
if(event->type() == QEvent::KeyPress)
{
QKeyEvent *keyEvent = static_cast<QKeyEvent *>(event);
if (keyEvent->key() == Qt::Key_Space)
{
m_ftime = 0;
ui->lcdNumber->display(m_ftime);
}
}
*/
if(obj == ui ->lcdNumber)
{
if (event->type() == QEvent::MouseButtonPress)
{
QMouseEvent *event2 = static_cast<QMouseEvent *>(event);
//如果事件为鼠标按下事件,把QEvent转换为QMouseEvent
if(event2 ->button() == Qt::LeftButton)
{
if(m_timer.isActive() == 1)
{
m_timer.stop();
}
else
{
m_timer.start(100);
}
}
else if(event2 ->button() == Qt::RightButton)
{
m_ftime = 0;
ui->lcdNumber->display(m_ftime);
}
}
}
return QObject::eventFilter(obj,event);
}