2012-04-16 2 views
1

Qt 프레임 워크 (4.7.4)를 사용하여 새로운 픽셀 데이터가 화면의 첫 번째 행에 추가되고 이전 픽셀이 모든 새로 고침에서 한 픽셀 아래로 스크롤되는 슬라이딩 디스플레이를 시연하려고합니다.Qt에서 스크롤하는 동안 감지되는 깜박임을 피하는 방법은 무엇입니까?

초당 20 회 리프레시되며 모든 리프레시마다 검정색 배경에 임의의 녹색 점 (픽셀)이 그려집니다.

문제는 다음과 같습니다. 매 리프레시마다 눈에 띄는 깜박 거림이 있습니다. 나는 웹을 통해 연구하고 코드를 최대한 최적화했다. QPainter (QWidget)와 QGraphicsScene (QGraphicsView) 모두에서 래스터 렌더링을 사용하려고 시도했지만 QGLWidget에서 OpenGL 렌더링을 사용하려고했습니다. 그러나, 결국 나는 여전히 같은 깜박임 문제가 있습니다.

이 깜박임이 발생할 수있는 이유는 무엇입니까? 내 LCD 모니터가 검은 색에서 녹색으로 전환 할 때 디스플레이를 새로 고칠 수 없다고 생각하기 시작합니다. 또한 검은 색 대신 회색 배경을 선택하면 깜박임이 발생하지 않는다는 것을 알게되었습니다.

+0

페인트 이벤트 전반에 걸쳐 픽스맵 페인팅을 위해 QPainter 인스턴스를 유지하는 것은 매우 드문 일입니다. QPainter가 여전히 pixmap에서 열려있는 동안 다른 페인트 장치에 픽스맵을 페인팅하면 동작이 정의되지 않을 수도 있습니다. –

+0

깜박임없는 응답 (메모리 비용)을 얻기 위해 활성화해야하는 이중 버퍼링에 관해 뭔가를 기억합니다. – RedX

+1

@RedX, AFAIK, Qt는 현재 이중 버퍼링을 지원하며 추가 이중 버퍼링 코드를 작성할 필요가 없습니다. – Anony

답변

1

당신이보고있는 효과는 순전히 psychovisual입니다. 그것은 소프트웨어 결함이 아니라 인간의 결함입니다. 나는 진지해. x의 값을 고정하여 확인할 수 있습니다. 깜박임이 없으므로 창에서 전체 픽스맵을 다시 칠하고 아무런 깜박임을 표시하지 않습니다.

정신 박동 깜박임은 스크롤 속도가 실시간으로 연결되어 있지 않을 때 발생합니다. 때로는 업데이트 사이의 시간이 CPU로드로 인해 또는 시스템 타이머 부정확으로 인해 달라질 수 있습니다. 우리의 시각 시스템은 두 개의 이미지를 통합하며 전체적인 밝기가 변경된 것처럼 보입니다.

배경을 회색으로 설정하여 이미지의 명암비를 낮추면 감지되는 깜박임이 줄어 듭니다. 이것은 효과가 psychovisual이라는 추가적인 단서이다.

다음은이 효과를 방지하는 방법입니다. 스크롤 거리가 시간과 어떻게 연관되어 있는지주의하십시오 (여기서는 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

픽스맵을 제자리에서 스크롤하지 않고 두 번째 픽스맵을 만들고 drawPixmap()을 사용하면 픽스맵 1에서 픽스맵 2 (스크롤 오프셋 포함) 한 줄만 복사하는 것이 좋습니다. 그런 다음 픽스맵에서 페인팅을 계속합니다. 2. 프레임이 끝나면 두 픽스맵에 대한 참조를 교환하고 다시 시작합니다.

하나의 메모리 영역에서 다른 메모리 영역으로 복사하는 것이 한 메모리 영역을 현재 위치에서 수정하는 것보다 더 쉽게 최적화 될 수 있다는 것입니다.

+0

이미지를 스크롤 할 때 성능 문제가없는 것 같지 않습니다. 1ms (1000fps) 이하의 paintEvent() 메서드를 성공적으로 종료합니다. 문제는 픽스맵을 디스플레이에 렌더링하는 것 같습니다. 검은 색 대신 회색 색을 배경으로 사용하면 눈에 띄는 깜박 거림이 없습니다. – Anony

+0

@Stefan, 이것을 백업 할 측정 값이 있습니까? –