4

私は Qt の初心者で、QPainter を使用したいと考えています。

私のプロセスは次のようなものです: 、などのシリアル ポートからデータ座標 (x、y)(1,1)(2,3)受け取ります。データを受け取るたびに、これらのポイントをウィンドウに描画したいと考えています。

QPainter はイベントで使用され、1 回だけ描画されます。データを受信するたびに使用するにはどうすればよいですか? 信号DataCome()とスロットがあるようにPaint().\


ところで、答えはたくさんあります。あなたのアドバイスはとても役に立ちます。

つまり、この場合、updata() または repaint() が機能します。

別の質問があります。シリアルポートが連続して座標点をコンピューターに送信し、すべての点をウィンドウに表示したいとします。いくつかの方法はありますか、それらのポイントをウィンドウの早い段階で残すことができます。新しいポイントをペイントする必要があるだけですか?matlab の「ホールドオン」のように。または、座標を格納するためのコンテナが必要で、それらすべてを非常に時間をかけずにペイントします。

4

4 に答える 4

4

うまくいけば、タスクを達成するために利用する必要があるメカニズムを理解するのに役立つ簡単な例を設定しました。

これはListener、データをリッスンして描画用に送信するクラスで構成されていWidgetます。私の例では、データがランダムに生成され、タイマーを使用して定期的に送信されるように設定しましたが、あなたの場合はシリアルポートデータになります。

あなたがやりたいことはプロットだと思うので、 を使用しpaintEventて単一のポイントを描画することはできません。毎回 1 つのポイントしか表示されず、ポイント データが蓄積されないためです。そのため、ピックスマップに描画する必要があります。に表示しますpaintEvent

Widget クラスと Listener クラスは次のとおりです。

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();
}

So what happens is a random data will be generated every 200 msec, sent to the Widget, where it is added to the pixmap and the Widget is updated to show the new entry.

EDIT: Considering how small a point (pixel) is, you may want to draw small circles instead. You can also color the point based on its data values, so you can get a gradient, for example low values might be green, but the higher it gets it can turn yellow and finally red...

You also might want to add the received data to a QVector<QPoint> if you will need it later, this can be done in the receiveData slot.

Another thing that might be worth mentioning - in the example everything is in range 0-200, the data, the plot window - very convenient. In reality this won't be the case, so you will need to map the data to the plot size, which may be changing depending on the widget size.

Here is a template I commonly use to normalize values in some range. You may want to simplify it a bit depending on your requirements.

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: Added the data vector to store all the received points in numerical form.

于 2013-08-28T06:44:37.400 に答える
4

QPainter は、QPaintDevice を継承する任意のオブジェクトを操作できます。

そのようなオブジェクトの 1 つが QWidget です。QWidget を再レンダリングする場合は、再レンダリングを必要とする長方形の領域で repaint または update を呼び出します。

repaintはすぐに paintEvent を発生させますが、 updateは paintEvent をイベント キューにポストします。これらは両方ともスロットであるため、別のスレッドからのシグナルに接続しても安全です。

次に、仮想メソッド「paintEvent」をオーバーライドし、ウィジェットでペインターを作成する必要があります。

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

Qt ヘルプで配布されている AnalogClock の例を例として見ることができます。

于 2013-08-28T03:52:32.000 に答える
1

QWidget の paintEvent でのみ QPainter を使用します。次のように実行できます。

受け取ったポイントのリストをメンバーとして保持し、paintEvent でこのリストを走査して、必要なポイントをペイントします。新しいポイントを受け取ったら、それをリストに追加して、widget->update() を呼び出します。これにより、ウィジェットはそれ自体を更新するように指示され、ウィジェットは適切なタイミングで paintEvent を呼び出します。

于 2013-08-28T05:53:37.770 に答える
0

QPixmapインスタンスを作成し、次のように描画します。

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

その後、ピックスマップで好きなことを行うことができます。ペイントイベントでペイントし、ディスクに書き込みます...

于 2013-08-28T06:13:01.153 に答える