在Qt中使用定时器有两种方法,一种是使用QObiect类的定时器;一种是使用QTimer类。
QObject类的定时器
QObject是所有Qt对象的基类,它提供了一个基本的定时器。通过QObject::startTimer(),可以把一个一毫秒为单位的时间间隔作为参数来开始定时器,这个函数返回一个唯一的整数定时器的标识符。这个定时器开始就会在每一个时间间隔"触发",直到明确的使用这个定时器的标识符来调用QObject::killTimer()结束。当定时器触发时,应用程序会发送一个QTimerEvent。在事件循环中,处理器按照事件队列的顺序来处理定时器事件。当处理器正忙于其它事件处理时,定时器就不能立即处理。
QObject类还提供定时期的功能。与定时器相关的成员函数有:startTimer()、timeEvent()、killTimer()。
QObject基类中的startTimer()和timerEvent()原型及说明如下:
int QObject::startTimer(int interval);
开始一个定时器并返回定时器ID,如果不能开始一个定时器,将返回0。定时器开始后,每隔interval毫秒间隔将触发一次超时事件,直到killTimer()被调用来删除定时器。如果interval为0,那么定时器事件每次发生时没有窗口系统事件处理。
virtual void QObject::timerEvent(QTimerEvent *event);
虚函数timerEvent()被重载来实现用户的超时事件处理函数。如果有多个定时器在运行,QTimerEvent::timerId()被用来查找指定定时器,对其进行操作。当定时器事件发生时,虚函数timerEvent()随着QTimerEvent事件参数类一起被调用,重载这个函数可以获得定时器事件。
QTimer类提供了定时器
信号和单触发定时器的功能,包含在头文件#include<QTimer.h>中,继承自QObject类。
它在内部使用定时器事件来提供更通用的定时器。QTimer很容易使用:
创建一个QTimer,使用start()来开始并且把它的timeout()连接到适当的槽。当这段时间过去了,它将会发射timeout()信号。注意当QTimer的父对象被销毁时,它也会被自动销毁。
你也可以使用静态的singleShot()函数来创建单触发定时器。
具体请看实例:
widget.h
#ifndef WIDGET_H
#define WIDGET_H
#include <QWidget>
#include <QTimerEvent>
#include <QDebug>
#include <QTimer>
namespace Ui {
class Widget;
}
class Widget : public QWidget
{
Q_OBJECT
public:
explicit Widget(QWidget *parent = 0);
~Widget();
void timerEvent(QTimerEvent *); // 对应的时间事件
public slots:
void doTimerService(); // 槽函数,与 m_timer 的 timeout 信号绑定
private slots:
void on_startBtn_clicked();
private:
Ui::Widget *ui;
QTimer m_timer; // 定义的定时器
int m_timeId; // timerEvent 对应的 timeId
};
#endif // WIDGET_H
widget.cpp
#include "widget.h"
#include "ui_widget.h"
Widget::Widget(QWidget *parent) :
QWidget(parent),
ui(new Ui::Widget)
{
ui->setupUi(this);
// 与对应的槽函数绑定
connect(&m_timer,SIGNAL(timeout()),this,SLOT(doTimerService()));
}
Widget::~Widget()
{
delete ui;
}
void Widget::timerEvent(QTimerEvent *e)
{
static int num = 0;
if(e->timerId() == m_timeId)
{
// 打印输出,偏于观察
qDebug() << "start timerEvent : " << ++ num; }}void Widget::doTimerService(){
// 打印输出,偏于观察
static int num = 0;
qDebug() << "do timer Service : " << ++ num;
}
void Widget::on_startBtn_clicked()
{
// 调用自定义的槽函数
m_timer.start(1000);
// 时间事件
m_timeId = startTimer(1000);
}
下面再来看下MFC中的使用
在对话框中使用定时器:
先来看下MFC中的定时器:
UINT SetTimer( UINT nIDEvent, UINT nElapse, void (CALLBACK EXPORT* lpfnTimer)( HWND, UINT, UINT, DWORD) );
其中:
UINT nIDEvent:定时器的ID,在一个程序中用这个ID来确定是那个定时器发送的消息。
UINT nElapse: 定义刷新时间,即间隔多长时间刷新一次,单位是毫秒。
void (CALLBACK EXPORT* lpfnTimer)( HWND, UINT, UINT, DWORD):回调函数的参数,实现刷新时所做的操作,一般情况下都设为0。
SetTimer函数用于创建一个计时器,KillTimer函数用于销毁一个计时器。计时器属于系统资源,使用完应及时销毁。 SetTimer的函数原型如下:UINT_PTR SetTimer( HWND hWnd, UINT_PTR nIDEvent, UINT uElapse, TIMERPROC lpTimerFunc ) ; 其中 hWnd是和timer关联的窗口句柄,此窗口必须为调用SetTimer的线程所有;如果hWnd为NULL,没有窗口和timer相关联并且nIDEvent参数被忽略 nIDEvent是timer的标识,为非零值;如果hWnd为NULL则被忽略;如果hWnd非NULL而且与timer相关联的窗口已经存在一个为此标识的timer,则此次SetTimer调用将用新的timer代替原来的timer。timer标识和窗口相关,两个不同的窗口可以拥有nIDEvent相同的tiemr uElapse是以毫秒指定的计时间隔值,范围为1毫秒到4,294,967,295毫秒(将近50天),这个值指示Windows每隔多久时间给程序发送WM_TIMER消息。
lpTimerFunc是一个回调函数的指针,俗称TimerFunc;如果lpTimerFunc为NULL,系统将向应用程序队列发送WM_TIMER消息;如果lpTimerFunc指定了一个值,DefWindowProc将在处理WM_TIMER消息时调用这个lpTimerFunc所指向的回调函数,因此即使使用TimerProc代替处理WM_TIMER也需要向窗口分发消息。
关于SetTimer的返回值:如果hWnd为NULL,返回值为新建立的timer的ID,如果hWnd非NULL,返回一个非0整数,如果SetTimer调用失败则返回0
KillTimer的函数原型为:BOOL KillTimer( HWND hWnd, UINT_PTR uIDEvent ) ; 参数意义同SetTimer。
关于KillTimer对消息队列中剩余未处理的WM_TIMER消息的影响,MSDN和Programming Windows上的说法完全相反。MSDN的说法很干脆:The KillTimer function does not remove WM_TIMER messages already posted to the message queue. 而petzold则说 The KillTimer call purges the message queue of any pending WM_TIMER messages. Your program will never receive a stray WM_TIMER message following a KillTimer call.
具体步骤如下:
afx_msg void OnTimer(UINT_PTR nIDEvent);
ON_WM_TIMER()
void CMFC_TimerDlg::OnTimer(UINT_PTR nIDEvent)
{
if (nIDEvent == TIMER)
{
//KillTimer(TIMER1);
TRACE("正在进行计数...\n");
static int num = 0;
CString cstr;
cstr.Format("测试Timer事件: %d",++ num);
GetDlgItem(IDC_STATIC)->SetWindowText(cstr);
CWnd *pWnd=GetDlgItem(IDC_STATIC);
pWnd->SetWindowText(cstr); //在Lable中设置新值,表明定时器已经工作。
}
CDialog::OnTimer(nIDEvent);
}
部分实例代码如下:
// MFC_TimerDlg.h : header file
//
#if !defined(AFX_MFC_TIMERDLG_H__8A52224E_4272_48A6_BAC3_58734FA47906__INCLUDED_)
#define AFX_MFC_TIMERDLG_H__8A52224E_4272_48A6_BAC3_58734FA47906__INCLUDED_
#if _MSC_VER > 1000
#pragma once
#endif // _MSC_VER > 1000
/
// CMFC_TimerDlg dialog
class CMFC_TimerDlg : public CDialog
{
// Construction
public:
CMFC_TimerDlg(CWnd* pParent = NULL); // standard constructor
// Dialog Data
//{{AFX_DATA(CMFC_TimerDlg)
enum { IDD = IDD_MFC_TIMER_DIALOG };
// NOTE: the ClassWizard will add data members here
//}}AFX_DATA
// ClassWizard generated virtual function overrides
//{{AFX_VIRTUAL(CMFC_TimerDlg)
protected:
virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV support
//}}AFX_VIRTUAL
// Implementation
protected:
HICON m_hIcon;
// Generated message map functions
//{{AFX_MSG(CMFC_TimerDlg)
virtual BOOL OnInitDialog();
afx_msg void OnSysCommand(UINT nID, LPARAM lParam);
afx_msg void OnPaint();
afx_msg HCURSOR OnQueryDragIcon();
afx_msg void OnButton();
afx_msg void OnTimer(UINT_PTR nIDEvent);
//}}AFX_MSG
DECLARE_MESSAGE_MAP()
};
//{{AFX_INSERT_LOCATION}}
// Microsoft Visual C++ will insert additional declarations immediately before the previous line.
#endif // !defined(AFX_MFC_TIMERDLG_H__8A52224E_4272_48A6_BAC3_58734FA47906__INCLUDED_)
// MFC_TimerDlg.cpp : implementation file
//
#include "stdafx.h"
#include "MFC_Timer.h"
#include "MFC_TimerDlg.h"
#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif
// 定义定时器
#define TIMER 1
/
// CAboutDlg dialog used for App About
class CAboutDlg : public CDialog
{
public:
CAboutDlg();
// Dialog Data
//{{AFX_DATA(CAboutDlg)
enum { IDD = IDD_ABOUTBOX };
//}}AFX_DATA
// ClassWizard generated virtual function overrides
//{{AFX_VIRTUAL(CAboutDlg)
protected:
virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV support
//}}AFX_VIRTUAL
// Implementation
protected:
//{{AFX_MSG(CAboutDlg)
//}}AFX_MSG
DECLARE_MESSAGE_MAP()
};
CAboutDlg::CAboutDlg() : CDialog(CAboutDlg::IDD)
{
//{{AFX_DATA_INIT(CAboutDlg)
//}}AFX_DATA_INIT
}
void CAboutDlg::DoDataExchange(CDataExchange* pDX)
{
CDialog::DoDataExchange(pDX);
//{{AFX_DATA_MAP(CAboutDlg)
//}}AFX_DATA_MAP
}
BEGIN_MESSAGE_MAP(CAboutDlg, CDialog)
//{{AFX_MSG_MAP(CAboutDlg)
// No message handlers
//}}AFX_MSG_MAP
END_MESSAGE_MAP()
/
// CMFC_TimerDlg dialog
CMFC_TimerDlg::CMFC_TimerDlg(CWnd* pParent /*=NULL*/)
: CDialog(CMFC_TimerDlg::IDD, pParent)
{
//{{AFX_DATA_INIT(CMFC_TimerDlg)
// NOTE: the ClassWizard will add member initialization here
//}}AFX_DATA_INIT
// Note that LoadIcon does not require a subsequent DestroyIcon in Win32
m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME);
}
void CMFC_TimerDlg::DoDataExchange(CDataExchange* pDX)
{
CDialog::DoDataExchange(pDX);
//{{AFX_DATA_MAP(CMFC_TimerDlg)
// NOTE: the ClassWizard will add DDX and DDV calls here
//}}AFX_DATA_MAP
}
BEGIN_MESSAGE_MAP(CMFC_TimerDlg, CDialog)
//{{AFX_MSG_MAP(CMFC_TimerDlg)
ON_WM_SYSCOMMAND()
ON_WM_PAINT()
ON_WM_QUERYDRAGICON()
ON_BN_CLICKED(IDC_BUTTON, OnButton)
ON_WM_TIMER()
//}}AFX_MSG_MAP
END_MESSAGE_MAP()
/
// CMFC_TimerDlg message handlers
BOOL CMFC_TimerDlg::OnInitDialog()
{
CDialog::OnInitDialog();
// Add "About..." menu item to system menu.
// IDM_ABOUTBOX must be in the system command range.
ASSERT((IDM_ABOUTBOX & 0xFFF0) == IDM_ABOUTBOX);
ASSERT(IDM_ABOUTBOX < 0xF000);
CMenu* pSysMenu = GetSystemMenu(FALSE);
if (pSysMenu != NULL)
{
CString strAboutMenu;
strAboutMenu.LoadString(IDS_ABOUTBOX);
if (!strAboutMenu.IsEmpty())
{
pSysMenu->AppendMenu(MF_SEPARATOR);
pSysMenu->AppendMenu(MF_STRING, IDM_ABOUTBOX, strAboutMenu);
}
}
// Set the icon for this dialog. The framework does this automatically
// when the application's main window is not a dialog
SetIcon(m_hIcon, TRUE); // Set big icon
SetIcon(m_hIcon, FALSE); // Set small icon
// TODO: Add extra initialization here
return TRUE; // return TRUE unless you set the focus to a control
}
void CMFC_TimerDlg::OnSysCommand(UINT nID, LPARAM lParam)
{
if ((nID & 0xFFF0) == IDM_ABOUTBOX)
{
CAboutDlg dlgAbout;
dlgAbout.DoModal();
}
else
{
CDialog::OnSysCommand(nID, lParam);
}
}
// If you add a minimize button to your dialog, you will need the code below
// to draw the icon. For MFC applications using the document/view model,
// this is automatically done for you by the framework.
void CMFC_TimerDlg::OnPaint()
{
if (IsIconic())
{
CPaintDC dc(this); // device context for painting
SendMessage(WM_ICONERASEBKGND, (WPARAM) dc.GetSafeHdc(), 0);
// Center icon in client rectangle
int cxIcon = GetSystemMetrics(SM_CXICON);
int cyIcon = GetSystemMetrics(SM_CYICON);
CRect rect;
GetClientRect(&rect);
int x = (rect.Width() - cxIcon + 1) / 2;
int y = (rect.Height() - cyIcon + 1) / 2;
// Draw the icon
dc.DrawIcon(x, y, m_hIcon);
}
else
{
CDialog::OnPaint();
}
}
// The system calls this to obtain the cursor to display while the user drags
// the minimized window.
HCURSOR CMFC_TimerDlg::OnQueryDragIcon()
{
return (HCURSOR) m_hIcon;
}
void CMFC_TimerDlg::OnButton()
{
// TODO: Add your control notification handler code here
// 开启定时器
static bool bTimSS = true;
if(bTimSS)
{
GetDlgItem(IDC_BUTTON)->SetWindowText(_T("停止"));
SetTimer(TIMER,1000,NULL);//启动定时器1,定时时间是1秒
TRACE("开启定时器...\n");
}
else
{
GetDlgItem(IDC_BUTTON)->SetWindowText(_T("开始"));
KillTimer(TIMER);
}
bTimSS = !bTimSS;
}
void CMFC_TimerDlg::OnTimer(UINT_PTR nIDEvent)
{
//重新加载图片,加载完后关闭定时器
if (nIDEvent == TIMER)
{
//KillTimer(TIMER1);
TRACE("正在进行计数...\n");
static int num = 0;
CString cstr;
cstr.Format("测试Timer事件: %d",++ num);
GetDlgItem(IDC_STATIC)->SetWindowText(cstr);
CWnd *pWnd=GetDlgItem(IDC_STATIC);
pWnd->SetWindowText(cstr); //在Lable中设置新值,表明定时器已经工作。
}
CDialog::OnTimer(nIDEvent);
}
以上,就是MFC与Qt中的定时器的简单应用。
分享下VC 6.0 相关的资料
相关的源代码分享地址