解像度が約15msのQtタイマーよりも正確なタイマーが必要なため、Windows APIのQueryPerformanceCounter()を使用して独自のタイマーを実装しようとしました。
私の最初のショットは、QObjectから継承し、毎秒信号を発する無限ループのタイマーを作成することでした。このタイマーをmoveToThread()を使用して独自のスレッドに移動しようとしました。これにより、メインウィンドウが毎秒更新され、すべてがブロックされることはありません。ただし、メインウィンドウが表示されることはなく、無限ループを削除すると->メインウィンドウが表示されます。
そこで、私はシングルショットアプローチを試しました。基本的な考え方は次のとおりです。
connect( highPerformanceTimer, SIGNAL(timer_tick()), this, SLOT(timeOutSlot()) );
connect( this, SIGNAL(graphics_updated()), highPerformanceTimer, SLOT(timer_start()));
したがって、タイマーが作動すると、ui(opengl)が更新され、更新の最後に、タイマーを再起動するための信号が生成されます。
それでも、UI更新コードの最後からタイマーの再起動を削除しない限り、メインウィンドウは表示されません。
デバッガーでは、コードが正常に機能しているように見え、タイマーからUIにジャンプして戻ってきます。ブレークポイントがないと、突然のセグメンテーション違反が発生します。
問題が発生する可能性のあるヒントや、Qtでこれを実装するためのより良い方法があるかどうかを教えていただければ幸いです。
編集:もう少しコード
highperformancetimer.h
#ifndef HIGHPERFORMANCETIMER_H
#define HIGHPERFORMANCETIMER_H
#include <QObject>
#include <windows.h>
class HighPerformanceTimer : public QObject
{
Q_OBJECT
public:
HighPerformanceTimer();
signals:
void timer_tick();
public slots:
void timer_start();
private:
// some variables
LARGE_INTEGER highPerformanceCounterValue, highPerformanceCounterFrequency, highPerformanceCounterValueOld;
int interval;
float value;
float last_tick_value;
};
#endif // HIGHPERFORMANCETIMER_H
highperformancetimer.cpp
#include "highperformancetimer.h"
#include "windows.h"
#include "QThread"
HighPerformanceTimer::HighPerformanceTimer()
{
QueryPerformanceFrequency(&highPerformanceCounterFrequency);
}
void HighPerformanceTimer::timer_start(){
float i = 0;
// just burn some time
while( i<1000000 ) i++;
emit HighPerformanceTimer::timer_tick();
}
メインのOpenGlウィジェットからのいくつかのコード:
HighPerformanceTimer *highPerformanceTimer;
protected slots:
virtual void timeOutSlot();
NeHeChapter5( QWidget *parent=0, char *name=0 ) : NeHeWidget( 50, parent, name )
{
highPerformanceTimer = new HighPerformanceTimer();
connect( highPerformanceTimer, SIGNAL(timer_tick()), this, SLOT(timeOutSlot()) );
connect( this, SIGNAL(graphics_updated()), highPerformanceTimer, SLOT(timer_start()));
highPerformanceTimer->moveToThread(&timerThread);
highPerformanceTimer->timer_start();
}
void NeHeChapter5::timeOutSlot(){
timeOut();
}
void NeHeChapter5::timeOut()
{
updateGL();
}
void NeHeChapter5::paintGL()
{
//opengl code *snip*
emit graphics_updated();
}