Using QPainter when every time I get some data

I am starting in Qt and I want to use QPainter.

My process looks like this: I get the coordinates of the data (x, y) from the serial port, such as (1,1) , (2,3) , etc. I want to draw these points in a window every time I get data.

I see that QPainter is used in events and just draws once. How can I use it every time I receive data? Same as the DataCome() signal and the Paint() slot. \


By the way, thanks for the answer. Your advice is very helpful.

In short, updata () or repaint () work in this case.

I have another question. Suppose the serial port continuously sends coordinate points to a computer, and I want to display the entire point in the window. Is there any method I can leave these points at an early stage in the window and I just need to draw new points? How to "stick" in Matlab. Or I need a container to store the coordinates, and paint them all the time.

+4
source share
4 answers

I set a quick example, which I hope will help you understand the mechanisms you need to use to complete your task.

It consists of a Listener class that listens for data and sends it to Widget for drawing. In my example, I set it up so that data is randomly generated and sent at regular intervals using a timer, but in your case it will be the data of your serial port.

Since I guess what you want to do is plot, you cannot use paintEvent to draw individual points, because every time it displays only one point, and the point data does not accumulate, you need to draw a pixmap that you just show in paintEvent .

Here are the Widget and Listener classes:

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

... and main:

 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, it happens that random data will be generated every 200 ms, sent to the Widget, where it is added to the pixmap, and the Widget updated to show a new record.

EDIT: given how small the dot (pixel) is, you can draw small circles. You can also colorize a point based on its data values ​​so that you can get a gradient, for example, low values ​​can be green, but the higher it can get yellow and finally red ...

You may also want to add the received data to the QVector<QPoint> , if you need it later, you can do this in the receiveData slot.

Another thing worth mentioning is that in the example everything is in the range 0-200, data, the graph window is very convenient. This is actually not the case, so you will need to match the data with the size of the graph, which may vary depending on the size of the widget.

Here is a pattern that I usually use to normalize values ​​in a certain range. You can 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 data vector to store all received points in numerical form.

+3
source

QPainter can work with any object that inherits from QPaintDevice.

One such object is QWidget. When a QWidget is required for reprocessing, you invoke a redraw or update with a rectangular area that requires re-rendering.

repaint immediately raises the paintEvent event, while the update sends paintEvent to the event queue. Both of these slots, so they should be safely connected to the signal from another stream.

Then you need to override the virtual method "paintEvent" and create a painter using the widget:

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

You can see the AnalogClock example, which is distributed using Qt's help as an example.

+4
source

You use QPainter only in paintEvent QWidget. You can do it as follows:

Keep the list of received points as a member and in paintEvent, move this list and draw the necessary points. When a new item is received, add it to the list and call widget-> update (). This means that the widget is updating itself, and the widget will call paintEvent when the time is right.

+1
source

Create an instance of QPixmap , then draw it like this:

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

Then you can do whatever you want with pixmap: paint it into a paint event, write it to disk ...

0
source

Source: https://habr.com/ru/post/1499282/


All Articles