天天看點

QTimer掉坑出坑過程

  最近遇到一個問題,就是關于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個!是以這個高精度的定時器還是要慎用!!

QTimer掉坑出坑過程