2012-04-16 32 views
1

Qtフレームワーク(4.7.4)を使用して、新しいピクセルデータが画面の最初の行に追加され、以前のピクセルがすべての更新時に1ピクセル下にスクロールされるスライド表示を試しています。Qtのスクロール中に知覚されるちらつきを避けるには?

1秒間に20回リフレッシュされ、リフレッシュごとに、黒い背景にランダムな緑の点(ピクセル)が描画されます。

問題は次のとおりです。リフレッシュごとに非常に目立つちらつきがあります。私はウェブを通して研究し、可能な限りコードを最適化しました。私は、QPainter(QWidget上)とQGraphicsScene(QGraphicsView上)の両方でラスタレンダリングを使用しようとしましたが、QGLWidgetでOpenGLレンダリングを使用しようとしました。しかし、最後には私はまだ同じフリッカーの問題があります。

このちらつきはどうしてですか?私は自分のLCDモニタが黒から緑への遷移のためにディスプレイをリフレッシュできないと思われ始めます。私はまた、黒の代わりに灰色の背景を選択すると、ちらつきが発生しないことに気付きました。

+0

ペイントイベント間でピックスマップペイントのQPainterインスタンスを保持することは非常に珍しいことです。 QPainterがまだpixmap上で開いている間に別のペイントデバイスにピックスマップをペイントすると、その動作が未定義になることがあります。 –

+0

私はちらつきのない応答(メモリを犠牲にして)を得るために起動する必要があるダブルバッファリングについて何か覚えています。 – RedX

+1

@RedX、AFAIK、Qtは現在ダブルバッファリングをサポートしており、追加のダブルバッファリングコードを書く必要はありません。 – Anony

答えて

1

あなたが見ている効果は純粋に精神的なものです。これは人間の欠陥であり、ソフトウェアの欠陥ではありません。私は真剣です。 xの値を固定することで確認することができます。フリッカーはないので、ウィンドウ上のピクスマップ全体をまだ再ペイントしていますが、フリッカーはありません。

スクロール速度がリアルタイムの経過に拘束されていない場合、心理的フリッカーが発生します。場合によっては、アップデートの間隔がCPUの負荷やシステムタイマーの不正確さのために変化する場合、我々のビジュアルシステムは2つのイメージを統合し、全体の明るさが変更されたかのように見えます。

背景を灰色に設定して画像のコントラスト比を下げると、知覚されるちらつきが減少することに気付きました。これは、その効果が精神的なものであるというさらなる手がかりです。

以下はこの効果を防​​ぐ方法です。スクロール距離が時間とどのように結びついているかに注目してください(ここでは1ms = 1ピクセル)。

#include <QElapsedTimer> 
#include <QPaintEvent> 
#include <QBasicTimer> 
#include <QApplication> 
#include <QPainter> 
#include <QPixmap> 
#include <QWidget> 
#include <QDebug> 

static inline int rand(int range) { return (double(qrand()) * range)/RAND_MAX; } 

class Widget : public QWidget 
{ 
    float fps; 
    qint64 lastTime; 
    QPixmap pixmap; 
    QBasicTimer timer; 
    QElapsedTimer elapsed; 
    void timerEvent(QTimerEvent * ev) { 
     if (ev->timerId() == timer.timerId()) update(); 
    } 
    void paintEvent(QPaintEvent * ev) { 
     qint64 time = elapsed.elapsed(); 
     qint64 delta = time - lastTime; 
     lastTime = time; 
     if (delta > 0) { 
      const float weight(0.05); 
      fps = (1.0-weight)*fps + weight*(1E3/delta); 

      if (pixmap.size() != size()) { 
       pixmap = QPixmap(size()); 
       pixmap.fill(Qt::black); 
      } 
      int dy = qMin((int)delta, pixmap.height()); 
      pixmap.scroll(0, dy, pixmap.rect()); 
      QPainter pp(&pixmap); 
      pp.fillRect(0, 0, pixmap.width(), dy, Qt::black); 
      for(int i = 0; i < 30; ++i){ 
       int x = rand(pixmap.width()); 
       pp.fillRect(x, 0, 3, dy, Qt::green); 
      } 
     } 
     QPainter p(this); 
     p.drawPixmap(ev->rect(), pixmap, ev->rect()); 
     p.setPen(Qt::yellow); 
     p.fillRect(0, 0, 100, 50, Qt::black); 
     p.drawText(rect(), QString("FPS: %1").arg(fps, 0, 'f', 0)); 
    } 

public: 
    explicit Widget(QWidget *parent = 0) : QWidget(parent), fps(0), lastTime(0), pixmap(size()) 
    { 
     timer.start(1000/60, this); 
     elapsed.start(); 
     setAttribute(Qt::WA_OpaquePaintEvent); 
    } 
}; 

int main(int argc, char *argv[]) 
{ 
    QApplication a(argc, argv); 
    Widget w; 
    w.show(); 
    return a.exec(); 
} 
-1

pixmapをスクロールしないで、2番目のpixmapを作成して、drawPixmap()を使用して、pixmap 1からpixmap 2まで(スクロールオフセット付きで)1行だけをコピーしてください。次に、ピックスマップでペインティングを続行します。2.フレームの後に、両方のピクスマップへの参照を交換し、最初からやり直します。

1つのメモリ領域から別のメモリ領域へのコピーは、1つのメモリ領域をインプレースで変更するより簡単に最適化することができます。

+0

画像をスクロールする際のパフォーマンス上の問題はないようです。 1ミリ秒(1000fps)でpaintEvent()メソッドから正常に終了します。この問題は、pixmapを表示することにあるようです。私は黒の代わりに背景として灰色を使用すると目立つちらつきはありません。 – Anony

+0

@Stefan、これをバックアップする測定値はありますか? –

関連する問題