浅谈 QT 中的 QTimer、QTimerEvent 与 MFC 中的 OnTimer

在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 相关的资料


点击打开链接


相关的源代码分享地址


点击打开链接




  • 0
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值