最近遇到一個問題,就是關于QTimer設定了10ms,結果不生效,很頭疼啊,查了快一天了,終于知道為什麼了?
先說下QTimer的使用方法:
m_delayHideTimer這是QTimer的對象。
connect(&m_delayHideTimer, SIGNAL(timeout()), this, SLOT(slotHideMenu())); //時間耗盡就會響應後面的回調函數。
m_delayHideTimer.setInterval(100) //重新設定定時器的時間。
m_delayHideTimer.stop(); //停掉定時器
m_delayHideTimer.start(50);//開始定時器
其他的用法,檢視QT asssistant就知道了不多啰嗦 上重點:
為什麼10ms的精度不生效:
這裡說下QT的源碼,裡面關于定時器的實作:
在QT的qeventdispatcher_win.cpp 檔案裡,有個函數具體如下:
void QEventDispatcherWin32Private::registerTimer(WinTimerInfo *t)
{
Q_ASSERT(internalHwnd);
Q_Q(QEventDispatcherWin32);
int ok = 0;
calculateNextTimeout(t, qt_msectime());
uint interval = t->interval;
if (interval == 0u) {
// optimization for single-shot-zero-timer
QCoreApplication::postEvent(q, new QZeroTimerEvent(t->timerId));
ok = 1;
} else if ((interval < 20u || t->timerType == Qt::PreciseTimer) && qtimeSetEvent) {
ok = t->fastTimerId = qtimeSetEvent(interval, 1, qt_fast_timer_proc, (DWORD_PTR)t,
TIME_CALLBACK_FUNCTION | TIME_PERIODIC | TIME_KILL_SYNCHRONOUS);
}
if (ok == 0) {
// user normal timers for (Very)CoarseTimers, or if no more multimedia timers available
ok = SetTimer(internalHwnd, t->timerId, interval, 0);
}
if (ok == 0)
qErrnoWarning("QEventDispatcherWin32::registerTimer: Failed to create a timer");
}
源碼可知,做了幾件事情:如果定時器的精度小于20ms,就會進入 qtimeSetEvent 這個函數,否則去走winapi 中的SetTimer,這個不多說。
qtimeSetEvent 這個函數的實作是:
qtimeSetEvent = (ptimeSetEvent)QSystemLibrary::resolve(QLatin1String("winmm"), "timeSetEvent");
qtimeKillEvent = (ptimeKillEvent)QSystemLibrary::resolve(QLatin1String("winmm"), "timeKillEvent");
winmm是windows的多媒體應用程式的接口,是個動态庫。去響應windows是的多媒體定時器。
這個定時器如果在精度不是特别高的情況下不要随便的使用,因為win會給這個頂定時器單獨配置設定一個線程,調用幾次timeSetEvent,就需要調用幾次timeKillEvent ,相對應的ID也要相同。
查了中外的各種論壇,有說同一個線程不能超過16個 也有說同一個程序不能超過16個 總之 超過16個就不生效的肯定是存在的,這裡還是盡量不要寫精度小于20Ms的定時器,以防萬一。後續有
這個方面的研究,再更新 先去改bug了。。。
後續驗證: 多媒體定時器一個程序隻能開16個!是以這個高精度的定時器還是要慎用!!
