2013-08-28 2 views
4

저는 Qt의 초보자이며 QPainter를 사용하고 싶습니다.데이터를받을 때마다 QPainter 사용

내 프로세스는 다음과 같습니다. (1,1), (2,3) 등의 직렬 포트에서 데이터 좌표 (x, y)를받습니다. 데이터를 수신 할 때마다 이러한 점을 창에 그리고 싶습니다.

QPainter는 이벤트에서 사용되며 한 번만 칠해집니다. 데이터를 수신 할 때마다 어떻게 사용할 수 있습니까? 그냥 같은 신호 DataCome() 및 슬롯 Paint() 있습니다. 그런데 \


을 들으 Answer.Your 조언에 많은 매우 유용합니다.

요약하면이 경우 updata() 또는 repaint()가 작동합니다.

다른 질문이 있습니다. 직렬 포트가 컴퓨터에 좌표 점을 보내기 위해 계속 연결되어 있다고 가정하면 이고 모든 점을 창에 표시하려고합니다. 거기에 몇 가지 방법이 있나요, 그 지점을 창문에 일찍 왔어, 그리고 난 그냥 새로운 지점을 페인트해야합니까?처럼 matlab에 "보류". 또는 좌표를 저장할 컨테이너가 필요하고 모든 시간을 아주 빨리 칠하십시오.

+0

위젯의 update() 메소드를 호출하고 paintEvent() 메소드 내부의 모든 것을 그립니다. – bkausbk

답변

3

작업을 수행하는 데 필요한 메커니즘을 이해하는 데 도움이되는 빠른 예제를 설정했습니다.

데이터를 수신하여 도면을 위해 Widget으로 전송하는 Listener 클래스로 구성됩니다.필자는 데이터를 무작위로 생성하여 타이머를 사용하여 일정한 간격으로 전송하도록 설정했지만 사용자의 경우에는 직렬 포트 데이터가됩니다.

플롯이 무엇인지 알고 싶으므로 paintEvent을 사용하면 단일 점을 그릴 수 없습니다. 점 하나만 표시되고 점 데이터가 누적되지 않기 때문에 점으로 그릴 필요가 있습니다. 픽스맵은 paintEvent에 표시됩니다.

class Widget : public QWidget { 
    Q_OBJECT 

public: 
    Widget(QWidget *parent = 0) : QWidget(parent) { 
     resize(200, 200); 
     p = new QPixmap(200, 200); 
    } 

protected: 
    void paintEvent(QPaintEvent *) { 
     QPainter painter(this); 
     painter.drawPixmap(0, 0, 200, 200, *p); 
    } 

public slots: 
    void receiveData(int x, int y) { 
     QPainter painter(p); 
     painter.setBrush(Qt::black); 
     QPoint point(x, y); 
     painter.drawPoint(point); 
     data.append(point); 
     repaint(); 
    } 

private: 
    QPixmap *p; 
    QVector<QPoint> data; 
}; 


class Listener : public QObject { 
    Q_OBJECT 

public: 
    Listener(QObject *p = 0) : QObject(p) { 
     QTimer * t = new QTimer(this); 
     t->setInterval(200); 
     connect(t, SIGNAL(timeout()), this, SLOT(sendData())); 
     t->start(); 
    } 

signals: 
    void dataAvaiable(int, int); 

public slots: 
    void sendData() { 
     emit dataAvaiable(qrand() % 200, qrand() % 200); 
    } 
}; 

... 메인 :

int main(int argc, char *argv[]) 
{ 
    QApplication a(argc, argv); 
    Widget w; 
    Listener l; 

    QObject::connect(&l, SIGNAL(dataAvaiable(int,int)), &w, SLOT(receiveData(int,int))); 

    w.show(); 

    return a.exec(); 
} 

그래서 무슨 위젯에 전송마다 200 밀리 초를 생성하는 임의의 데이터이며, 여기에

은 위젯과 리스너 클래스입니다 여기서 pixmap에 추가되고 Widget은 새 항목을 표시하도록 업데이트됩니다.

편집 : 포인트 (픽셀)가 얼마나 작은지를 고려하여 작은 원을 그릴 수 있습니다. 또한 데이터 값을 기준으로 점의 색상을 지정할 수 있으므로 그라디언트를 얻을 수 있습니다 (예 : 낮은 값은 초록색 일 수 있지만 높으면 높을수록 노란색으로 바뀌며 마지막으로 빨간색으로 변할 수 있음).

나중에 필요할 경우 수신 된 데이터를 QVector<QPoint>에 추가하려면 receiveData 슬롯에서 수행 할 수 있습니다.

언급 할 가치가있는 또 다른 사항은 예제에서 모든 것이 0-200 범위의 데이터, 플롯 창에 있습니다. 매우 편리합니다. 현실에서는 그렇지 않을 것이므로 데이터를 플롯 크기에 매핑해야합니다. 플롯 크기는 위젯 크기에 따라 달라질 수 있습니다.

다음은 일반적으로 일부 범위의 값을 정규화하기 위해 사용하는 템플릿입니다. 요구 사항에 따라 약간 단순화 할 수 있습니다.

template <typename Source, typename Target> 
Target normalize(Source s, Source max, Source min, Target floor, Target ceiling) { 
    return ((ceiling - floor) * (s - min)/(max - min) + floor); 
} 

Edit2가이 : 숫자 형태로 수신 된 모든 포인트를 저장하는 data 벡터를 추가했습니다.

+0

위젯에 따라 pixmap 크기를 조정하려면 코드에 resizeEvent를 추가하는 것이 가장 좋습니다. – erelender

+0

@erelender - 내가 마지막으로 작성한 수정 내용을 확인하십시오. – dtech

+0

나는 또한 위젯을 업데이트하는 방법을 묻는 대신 유즈 케이스를 모른 채 버퍼링 솔루션을 제공한다고 생각합니다. 그럼에도 불구하고, 그것은 좋은 설명 적 대답입니다. – erelender

4

QPainter는 QPaintDevice에서 상속 한 모든 개체에서 작동 할 수 있습니다.

이러한 오브젝트 중 하나는 QWidget입니다. QWidget을 다시 렌더링하기를 원할 때 재 렌더링이 필요한 직사각형 영역을 사용하여 다시 그리기 또는 업데이트를 호출합니다.

다시 그리기 즉시 갱신 동안, 게시물 이벤트 큐에 paintEvent를 발생하는 paintEvent됩니다. 이 두 슬롯은 슬롯이므로 다른 스레드의 신호에 연결하는 것이 안전해야합니다.

void MyWidget::paintEvent(QPaintEvent * evt) 
{ 
    QPainter painter(this); 
    //... do painting using painter. 
} 

당신은 예를 들어 Qt는 도움말과 함께 배포되는 AnalogClock의 예를 볼 수 있습니다 :

그런 다음 가상 방법 "paintEvent"를 무시하고 위젯 화가를 만들어야합니다.

1

QPainter는 QWidget의 paintEvent에서만 사용합니다. 다음과 같이 할 수 있습니다 :

수신 된 포인트 목록을 member로 유지하고 paintEvent에서이 목록을 탐색하고 필요한 포인트를 페인트합니다. 새로운 포인트가 수신되면리스트에 추가하고 widget-> update()를 호출하십시오. 이것은 위젯이 자신을 새로 고치도록하고, 위젯은 시간이 맞으면 paintEvent를 호출합니다.

+0

이러한 모든 탐색은 CPU 시간을 필요로 할 것입니다. 특히 OP가 새로운 데이터를 수신 할 때마다 업데이트를 원한다고 생각한 경우를 고려하십시오. 따라서 픽스맵을 그리면 데이터 포인트가 누적되어 표시됩니다. 매번 포인트를 횡단하고 그리는 것이 더 효율적입니다. – dtech

+0

맞습니다. 그렇지만 pixmap을 사용하면 점 목록을 관리 할 수 ​​없습니다. 즉, 점 검색에 대한 픽스맵을 참조 할 수 없으며 나중에 점이 제거 될 때 어떤 일이 발생합니까? 전체 픽스맵을 다시 페인트해야한다. 필자는 픽스맵을 사용하는 것이 성능 측면에서 여전히 더 효율적이라고 주장 할 수는 있지만, 픽스맵을 사용하는 것이이 특정 문제에 대한 해결책은 아니지만 범용 버퍼링 방식에 가깝다고 생각합니다. – erelender

+0

필요한 경우 포인트를 저장할 수 있지만 시각적 인 목적으로 만 포인트를 저장할 수 있습니다. pixmap이 많은 수의 점보다 더 빨리 그려지는 것은 확실합니다. – dtech

0

는 다음과 같이 그립니다하는 QPixmap 인스턴스를 만듭니다

QPixmap pixmap(100, 100); 
QPainter p(&pixmap); 
// do some drawing 

당신은 당신이 원하는대로 픽스맵으로 수행 할 수 있습니다, 페인트 이벤트에 페인트 디스크에 쓰기

관련 문제