每次收到一些数据时都使用QPainter

时间:2013-08-28 02:27:59

标签: c++ qt qpainter

我是Qt的初学者,我想使用QPainter。

我的过程是这样的:我从串口接收数据坐标(x,y),如(1,1)(2,3)等。我想每次在窗口中绘制这些点接收数据。

我看到QPainter用于事件,只画了一次。我每次收到数据时如何使用它?就像有一个信号DataCome()和一个插槽Paint()。\


顺便说一下,答案很多。你的建议很有用。

简而言之,updata()或repaint()在这种情况下起作用。

我有另一个问题。 假设,串口连续发送坐标点给计算机, 我想显示窗口中的所有点。有没有一些方法,我可以把这些点留在窗口的早期,我只需要绘制新点?就像在matlab中“保持”一样。或者我需要一个容器来存储坐标,并且非常及时地绘制所有这些坐标。

4 个答案:

答案 0 :(得分:4)

QPainter可以对任何继承自QPaintDevice的对象进行操作。

一个这样的对象是QWidget。当想要重新渲染QWidget时,可以使用需要重新渲染的矩形区域调用重绘或更新。

repaint 会立即导致paintEvent发生,而 update 会在事件队列上发布paintEvent。这两个都是插槽,因此将它们连接到另一个线程的信号应该是安全的。

然后你必须覆盖虚拟方法“paintEvent”并用小部件创建一个画家:

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

您可以查看以Qt帮助分发的AnalogClock示例。

答案 1 :(得分:3)

我已经设置了一个快速示例,希望能帮助您了解完成任务所需的机制。

它由一个Listener类组成,该类侦听数据并将其发送到Widget进行绘制。在我的示例中,我已将其设置为使得数据随机生成并使用计时器定期发送,但在您的情况下将是您的串行端口数据。

由于我假设你想要做的是一个情节,你不能使用paintEvent绘制单个点,因为每次它只显示一个点并且点数据不会累积,所以你需要绘制到一个像素图,它只显示在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();
}

所以会发生的是每200毫秒生成一个随机数据,发送到Widget,在那里它被添加到像素图中,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向量,以数字形式存储所有收到的点。

答案 2 :(得分:1)

仅在QWidget的paintEvent中使用QPainter。你可以这样做:

将收到的点列表作为成员保存在paintEvent中,遍历此列表并绘制所需的点。收到新点后,将其添加到列表中并调用widget-&gt; update()。这告诉窗口小部件自己刷新,窗口小部件将在时机成功时调用paintEvent。

答案 3 :(得分:0)

创建一个QPixmap实例,然后像这样绘制:

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

然后您可以随意使用pixmap:在paint事件中绘制它,将其写入磁盘......