我是Qt的初学者,我想使用QPainter。
我的过程是这样的:我从串口接收数据坐标(x,y),如(1,1)
,(2,3)
等。我想每次在窗口中绘制这些点接收数据。
我看到QPainter用于事件,只画了一次。我每次收到数据时如何使用它?就像有一个信号DataCome()
和一个插槽Paint()
。\
顺便说一下,答案很多。你的建议很有用。
简而言之,updata()或repaint()在这种情况下起作用。
我有另一个问题。 假设,串口连续发送坐标点给计算机, 我想显示窗口中的所有点。有没有一些方法,我可以把这些点留在窗口的早期,我只需要绘制新点?就像在matlab中“保持”一样。或者我需要一个容器来存储坐标,并且非常及时地绘制所有这些坐标。
答案 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事件中绘制它,将其写入磁盘......