簡述
QTimer類提供了重復和單次觸發信號的定時器。
QTimer類為定時器提供了一個高級別的編程接口。很容易使用:首先,創建一個QTimer,連接timeout()信號到適當的槽函數,並調用start(),然后在恆定的時間間隔會發射timeout()信號。
注意:當QTimer的父對象被銷毀時,它也會被自動銷毀。
詳細說明
在Qt之模擬時鍾中,1秒(1000毫秒)更新一次:
QTimer *timer = new QTimer(this);
connect(timer, SIGNAL(timeout()), this, SLOT(update()));
timer->start(1000);
start()之后,每秒都會調用update()。
可以通過設置setSingleShot(true)來讓定時器只執行一次。也可以使用靜態函數QTimer::singleShot():
QTimer::singleShot(200, this, SLOT(updateCaption()));
在多線程程序中,可以在一個有事件循環的任何線程中使用QTimer。使用QThread::exec(),從非GUI線程啟動一個事件循環。 Qt使用定時器的線程關聯,以確定哪個線程會發出timeout()信號。正因為如此,你必須在它的線程中啟動和停止定時器,不可能從另一個線程啟動定時器。
作為一個特例,一旦窗口系統事件隊列中的所有事件都已經被處理完,一個定時為0的QTimer就會到時間了。當需要提供流暢的用戶界面時,可以用這來做比較繁重的工作。
QTimer *timer = new QTimer(this);
connect(timer, SIGNAL(timeout()), this, SLOT(processOneThing()));
timer->start();
這時,processOneThing()將會被重復調用並且應該很快返回(通常在處理一個數據項之后),這樣Qt可以把事件傳送給窗口部件,並且一旦它完成這個工作就停止這個定時器。這是在圖形用戶界面應用程序中實現繁重的工作的一個典型方法,現在多線程可以在越來越多的平台上使用,我們希望0-毫秒QTimer對象最終被線程替代。
精度
定時器的精度取決於底層操作系統和硬件。絕大多數平台支持精度為1毫秒,盡管定時器的准確性在許多現實世界的情況下和這不相符。
准確性也取決於定時器類型(Qt::TimerType)。對於Qt::PreciseTimer來說,QTimer將試圖保持精確度在1毫秒。精確的定時器也從來不會比預計的還要早超時。
對於Qt::CoarseTimer和Qt::VeryCoarseTimer類型,QTimer可能早於預期,在間隔之內被喚醒:Qt::CoarseTimer為間隔的5%,Qt::VeryCoarseTimer為500毫秒。
枚舉Qt::TimerType:
常量 | 值 | 描述 |
---|---|---|
Qt::PreciseTimer | 0 | 精確的定時器,盡量保持毫秒精度。 |
Qt::CoarseTimer | 1 | 粗略的定時器,盡量保持精度在所需的時間間隔5%范圍內。 |
Qt::VeryCoarseTimer | 2 | 很粗略的定時器,只保留完整的第二精度。 |
在UNIX (包括: Linux、OS X、iOS)中,Qt將為Qt::PreciseTimer保持毫秒精度,對於Qt::CoarseTimer,間隔將調整到5%,使定時器與其他定時器匹配或在差不多在同一時間,目標是讓大多數定時器在同一時間醒來,從而減少CPU喚醒和功耗。
在Windows上,Qt將為Qt::PreciseTimer使用Windows的多媒體定時器工具(如果可用),為Qt::CoarseTimer和Qt::VeryCoarseTimer使用正常的Windows定時器。
所有平台上,Qt::VeryCoarseTimer的間隔被四舍五入到最接近完整的第二位(例如:23500ms的時間間隔將被舍入到24000ms,20300ms舍入至20000)。
替代QTimer
另一個使用QTimer的方法:為你的對象調用QObject::startTimer(),在你的類中(必須繼承QObject)重新實現QObject::timerEvent()事件處理器。缺點是timerEvent()不支持像單次觸發定時器或信號那樣的高級特性。
另一個選擇是QBasicTimer。它通常比使用QObject::startTimer() 直接。可以查看助手中Timers描述的三種方法。
一些操作系統限制可能會限制定時器的數量,Qt會盡力在限制范圍內工作。
可參考:QBasicTimer、QTimerEvent、QObject::timerEvent()、Timers、Analog Clock Example、Wiggly Example。
成員函數
bool isActive() const
如果定時器正在運行,返回true,否則返回false。int remainingTime() const
返回定時器的剩余時間(毫秒為單位),直到超時。如果定時器不活躍,返回值是-1。如果定時器過期,返回值為0。
void setInterval(int msec)
設置超時間隔(毫秒為單位)。默認值是0,這時,一旦窗口系統事件隊列中的所有事件都已經被處理完,一個時間間隔為0的QTimer就會觸發。
void setSingleShot(bool singleShot)
設置定時器是否為單次觸發。單次觸發定時器只觸發一次,非單次的話,則每過一個時間間隔都會觸發。
void setTimerType(Qt::TimerType atype)
設置定時器的准確性。默認值是Qt::CoarseTimer。int timerId() const
如果定時器正在運行,返回定時器的ID,否則返回-1。void start(int msec)
啟動或重新啟動一個超時時間間隔為毫秒的定時器。如果定時器正在運行,它將被停止和重新啟動。如果singleShot為true,定時器將只激活一次。
void start()
同上,重載了start()。void stop()
停止定時器。
信號
void timeout()
定時器超時后,這個信號被發射。注意:這是一個私有的信號。它可以在信號連接使用,但不能由用戶發出。
示例
下面,我們以QTimer為例,利用開始和停止按鈕來操作一個進度條的更新。
效果
源碼
QPushButton *pStartButton = new QPushButton(this);
QPushButton *pStopButton = new QPushButton(this);
m_pProgressBar = new QProgressBar(this);
m_pTimer = new QTimer();
pStartButton->setText(QString::fromLocal8Bit("開始"));
pStopButton->setText(QString::fromLocal8Bit("停止"));
m_pProgressBar->setRange(0, 100);
m_pProgressBar->setValue(50);
// 設置超時間隔
m_pTimer->setInterval(1000);
// 連接信號槽
connect(pStartButton, SIGNAL(clicked(bool)), m_pTimer, SLOT(start()));
connect(pStopButton, SIGNAL(clicked(bool)), m_pTimer, SLOT(stop()));
connect(m_pTimer, SIGNAL(timeout()), this, SLOT(updateProgress()));
// 槽函數
void MainWindow::updateProgress()
{
// 獲取當前進度值,+1
int nCurrentValue = m_pProgressBar->value();
nCurrentValue++;
if (nCurrentValue >= 100)
m_pTimer->stop();
// 設置新的進度值
m_pProgressBar->setValue(nCurrentValue);
}
在槽函數updateProgress()中,首先通過m_pProgressBar->value()來獲取當前進度值,然后加1,當進度大於等於100時停止定時器(再繼續執行已經沒任何意義了,因為進度已經達到了100,而且不停止還消耗資源),然后設置進度條的值。