Draw in QPainter
-
hi,
im trying to periodically generate random lines and append them to each other to create a path. i use QPainteri'm calling my custom method in the paintEvent
but all i get is
QPainter::setPen: Painter not active
how should i activate it ?is there a more suited qt class for what i'm doing
thanks
#ifndef MAINWINDOW_H #define MAINWINDOW_H #include <QMainWindow> #include <QPainter> #include <QTimer> #include <QDebug> QT_BEGIN_NAMESPACE namespace Ui { class MainWindow; } QT_END_NAMESPACE class MainWindow : public QMainWindow { Q_OBJECT public: MainWindow(QWidget *parent = nullptr); ~MainWindow(); protected: void paintEvent(QPaintEvent *event) { Q_UNUSED(event) drawLineW(qrand()*100, qrand()*100,(qrand()%10 > 5)?true:false); } void drawLineW(int x, int y, bool down){ qDebug()<<down; if(down){ painter->setPen(QPen(Qt::blue, 8, Qt::DashDotLine, Qt::RoundCap)); }else{ painter->setPen(QPen(Qt::red, 2, Qt::DashDotLine, Qt::RoundCap)); } painter->drawLine(lastX,lastY,x,y); lastX = x; lastY = y; } private: int lastX=0; int lastY=0; QPainter* painter; QTimer * drawTimer; Ui::MainWindow *ui; }; #endif // MAINWINDOW_H //________________________________________ #include "mainwindow.h" #include "ui_mainwindow.h" MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent) , ui(new Ui::MainWindow) { ui->setupUi(this); drawTimer = new QTimer(this); painter = new QPainter(this); drawTimer->setInterval(100); QObject::connect(drawTimer,&QTimer::timeout,[=](){ update(); }); drawTimer->start(); } MainWindow::~MainWindow() { delete ui; }
-
This was 1000 times easier using Graphics View...
class MainWindow : public QMainWindow { Q_OBJECT public: MainWindow(QWidget *parent = nullptr); ~MainWindow(); private: int oldX=0; int oldY=0; Ui::MainWindow *ui; QGraphicsScene *scene; QTimer *drawTimer; QGraphicsLineItem *vect; QVector <QPoint> path; int nLine = 0; void createPath(){ for(int i=1;i<20;i++){ path.append(QPoint(i*10,(i%2)*10)); } } }; //___ cpp MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent) , ui(new Ui::MainWindow) { ui->setupUi(this); scene = new QGraphicsScene(this); ui->graphicsView->setScene(scene); drawTimer = new QTimer(this); drawTimer->setInterval(50); createPath(); QObject::connect(drawTimer,&QTimer::timeout,[=](){ if(nLine>=path.length()){ drawTimer->stop(); return; } int newX = path.at(nLine).x(); int newY = path.at(nLine).y(); vect = scene->addLine(oldX,oldY,newX,newY); oldX= newX; oldY= newY; nLine++; }); drawTimer->start(); }
-
You need to create the painter in the paint event, I think, just like in the docs: https://doc.qt.io/qt-5/qpainter.html
-
You need to create the painter in the paint event, I think, just like in the docs: https://doc.qt.io/qt-5/qpainter.html
-
hi @sierdzio
that is the first test thing i did, yes.but if i create one QPainter on the stack it is deleted every time
i want to keep the old path picture and add new line to it
@LeLev Why don't you then simply append the new lines to a member QVector and simply call drawLines(vector) inside the paint event?
-
hi @sierdzio
that is the first test thing i did, yes.but if i create one QPainter on the stack it is deleted every time
i want to keep the old path picture and add new line to it
@LeLev said in Draw in QPainter:
hi @sierdzio
that is the first test thing i did, yes.but if i create one QPainter on the stack it is deleted every time
i want to keep the old path picture and add new line to it
Then at the end of paint event, save the painter to a picture (QPixmap). Then in next paint event, first paint the pixmap, then add your new line to it (and save another pixmap).
-
Perhaps you can work around this by using member pointer like you do, but then calling QPainter::begin() in the beginning of your event handler. I'm not sure if it will work, though.
-
Perhaps you can work around this by using member pointer like you do, but then calling QPainter::begin() in the beginning of your event handler. I'm not sure if it will work, though.
@J-Hilk i will try,
but that means every time you add a new line, you re-draw all the lines in the vector (from the beginning) ?@sierdzio
like this, the first line is drawn and then a crash.void paintEvent(QPaintEvent *event) { Q_UNUSED(event) if(!painter->isActive()){ painter->begin(this); } drawLineW(qrand()*100, qrand()*100,(qrand()%10 > 5)?true:false); }
is there an other type that will not clear the screen, and i can simply add lines ? im not forced to use QPainter
-
@J-Hilk i will try,
but that means every time you add a new line, you re-draw all the lines in the vector (from the beginning) ?@sierdzio
like this, the first line is drawn and then a crash.void paintEvent(QPaintEvent *event) { Q_UNUSED(event) if(!painter->isActive()){ painter->begin(this); } drawLineW(qrand()*100, qrand()*100,(qrand()%10 > 5)?true:false); }
is there an other type that will not clear the screen, and i can simply add lines ? im not forced to use QPainter
@LeLev said in Draw in QPainter:
you re-draw all the lines in the vector (from the beginning) ?
You can draw in a QImage when you add a line and draw the image in paintEvent
-
@LeLev said in Draw in QPainter:
you re-draw all the lines in the vector (from the beginning) ?
You can draw in a QImage when you add a line and draw the image in paintEvent
hi
@jsulm said in Draw in QPainter:You can draw in a QImage
sorry i can't find methods to draw in a QImage nor in QPaintDevice
i have to pass the image to my QPainter so i can draw right ?
#ifndef MAINWINDOW_H #define MAINWINDOW_H #include <QMainWindow> #include <QPainter> #include <QTimer> #include <QVector> #include <QDebug> QT_BEGIN_NAMESPACE namespace Ui { class MainWindow; } QT_END_NAMESPACE class MainWindow : public QMainWindow { Q_OBJECT public: MainWindow(QWidget *parent = nullptr); ~MainWindow(); protected: void paintEvent(QPaintEvent *event) { Q_UNUSED(event) if(!painter->isActive()){ painter->begin(this); } drawLineW(qrand()*100, qrand()*100,(qrand()%10 > 5)?true:false); } void drawLineW(int x, int y, bool down){ painter->drawLine(lastX,lastY,x,y); lastX = x; lastY = y; } private: int lastX=0; int lastY=0; //QVector <QPoint> lines; QImage pathImg; QPainter* painter; QTimer * drawTimer; Ui::MainWindow *ui; }; #endif // MAINWINDOW_H //__________________________________ MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent) , ui(new Ui::MainWindow) { ui->setupUi(this); drawTimer = new QTimer(this); painter = new QPainter(&pathImg); drawTimer->setInterval(100); QObject::connect(drawTimer,&QTimer::timeout,[=](){ update(); }); drawTimer->start(); }
sorry im struggling so hard now, i can't get this done fo 3 houres.. I m not used to QWidgets at all.
i did the same thing in qml/js in about 10minutes -
hi
@jsulm said in Draw in QPainter:You can draw in a QImage
sorry i can't find methods to draw in a QImage nor in QPaintDevice
i have to pass the image to my QPainter so i can draw right ?
#ifndef MAINWINDOW_H #define MAINWINDOW_H #include <QMainWindow> #include <QPainter> #include <QTimer> #include <QVector> #include <QDebug> QT_BEGIN_NAMESPACE namespace Ui { class MainWindow; } QT_END_NAMESPACE class MainWindow : public QMainWindow { Q_OBJECT public: MainWindow(QWidget *parent = nullptr); ~MainWindow(); protected: void paintEvent(QPaintEvent *event) { Q_UNUSED(event) if(!painter->isActive()){ painter->begin(this); } drawLineW(qrand()*100, qrand()*100,(qrand()%10 > 5)?true:false); } void drawLineW(int x, int y, bool down){ painter->drawLine(lastX,lastY,x,y); lastX = x; lastY = y; } private: int lastX=0; int lastY=0; //QVector <QPoint> lines; QImage pathImg; QPainter* painter; QTimer * drawTimer; Ui::MainWindow *ui; }; #endif // MAINWINDOW_H //__________________________________ MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent) , ui(new Ui::MainWindow) { ui->setupUi(this); drawTimer = new QTimer(this); painter = new QPainter(&pathImg); drawTimer->setInterval(100); QObject::connect(drawTimer,&QTimer::timeout,[=](){ update(); }); drawTimer->start(); }
sorry im struggling so hard now, i can't get this done fo 3 houres.. I m not used to QWidgets at all.
i did the same thing in qml/js in about 10minutes@LeLev said in Draw in QPainter:
i have to pass the image to my QPainter so i can draw right ?
You can use setBackground() or drawPixmap() first, then proceed with your
drawLine()
call. -
hi
@jsulm said in Draw in QPainter:You can draw in a QImage
sorry i can't find methods to draw in a QImage nor in QPaintDevice
i have to pass the image to my QPainter so i can draw right ?
#ifndef MAINWINDOW_H #define MAINWINDOW_H #include <QMainWindow> #include <QPainter> #include <QTimer> #include <QVector> #include <QDebug> QT_BEGIN_NAMESPACE namespace Ui { class MainWindow; } QT_END_NAMESPACE class MainWindow : public QMainWindow { Q_OBJECT public: MainWindow(QWidget *parent = nullptr); ~MainWindow(); protected: void paintEvent(QPaintEvent *event) { Q_UNUSED(event) if(!painter->isActive()){ painter->begin(this); } drawLineW(qrand()*100, qrand()*100,(qrand()%10 > 5)?true:false); } void drawLineW(int x, int y, bool down){ painter->drawLine(lastX,lastY,x,y); lastX = x; lastY = y; } private: int lastX=0; int lastY=0; //QVector <QPoint> lines; QImage pathImg; QPainter* painter; QTimer * drawTimer; Ui::MainWindow *ui; }; #endif // MAINWINDOW_H //__________________________________ MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent) , ui(new Ui::MainWindow) { ui->setupUi(this); drawTimer = new QTimer(this); painter = new QPainter(&pathImg); drawTimer->setInterval(100); QObject::connect(drawTimer,&QTimer::timeout,[=](){ update(); }); drawTimer->start(); }
sorry im struggling so hard now, i can't get this done fo 3 houres.. I m not used to QWidgets at all.
i did the same thing in qml/js in about 10minutes@LeLev said in Draw in QPainter:
sorry i can't find methods to draw in a QImage
Sorry, it's drawPixmap.
"i have to pass the image to my QPainter so i can draw right ?" - no, use one of the drawPixmap() methods..
-
@LeLev said in Draw in QPainter:
i have to pass the image to my QPainter so i can draw right ?
You can use setBackground() or drawPixmap() first, then proceed with your
drawLine()
call.i call begin() as you suggested
and i also have to call end() at the end of my method.now i can see my randomly generated lines, but every time i add a line the rest of lines are deleted/cleaned.
@sierdzio said in Draw in QPainter:
Then at the end of paint event, save the painter to a picture (QPixmap). Then in next paint event, first paint the pixmap
now i'm trying to do this.
There is a QPainter::drawPixmap to draw the saved image, but i can't find how to save the QPainter content to a QPixmap first, can you please give me a hint ? -
almost working, just need to fix the save and reload feature
class MainWindow : public QMainWindow { Q_OBJECT public: MainWindow(QWidget *parent = nullptr); ~MainWindow(); protected: void paintEvent(QPaintEvent *event) { Q_UNUSED(event) if(!painter->isActive()){ painter->begin(this); } drawLineW(qrand()%250, qrand()%250,(qrand()%10 > 5)?true:false); } void drawLineW(int x, int y, bool down){ // load last path/picture painter->drawPixmap(0,0,this->height(),this->width(),oldPath); if(down){ painter->setPen(QPen(Qt::blue, 3, Qt::DashDotLine, Qt::RoundCap)); }else{ painter->setPen(QPen(Qt::red, 3, Qt::DashDotLine, Qt::RoundCap)); } painter->drawLine(lastX,lastY,x,y); painter->end(); lastX = x; lastY = y; // save current path/picture oldPath = QPixmap::fromImage(oldPathImg); } private: int lastX=0; int lastY=0; QImage oldPathImg; QPixmap oldPath; QPainter* painter; QTimer * drawTimer; Ui::MainWindow *ui; }; #endif // MAINWINDOW_H // ___ MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent) , ui(new Ui::MainWindow) { ui->setupUi(this); drawTimer = new QTimer(this); painter = new QPainter(&oldPathImg); drawTimer->setInterval(1000); QObject::connect(drawTimer,&QTimer::timeout,[=](){ update(); }); drawTimer->start(); }
-
This was 1000 times easier using Graphics View...
class MainWindow : public QMainWindow { Q_OBJECT public: MainWindow(QWidget *parent = nullptr); ~MainWindow(); private: int oldX=0; int oldY=0; Ui::MainWindow *ui; QGraphicsScene *scene; QTimer *drawTimer; QGraphicsLineItem *vect; QVector <QPoint> path; int nLine = 0; void createPath(){ for(int i=1;i<20;i++){ path.append(QPoint(i*10,(i%2)*10)); } } }; //___ cpp MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent) , ui(new Ui::MainWindow) { ui->setupUi(this); scene = new QGraphicsScene(this); ui->graphicsView->setScene(scene); drawTimer = new QTimer(this); drawTimer->setInterval(50); createPath(); QObject::connect(drawTimer,&QTimer::timeout,[=](){ if(nLine>=path.length()){ drawTimer->stop(); return; } int newX = path.at(nLine).x(); int newY = path.at(nLine).y(); vect = scene->addLine(oldX,oldY,newX,newY); oldX= newX; oldY= newY; nLine++; }); drawTimer->start(); }