Important: Please read the Qt Code of Conduct - https://forum.qt.io/topic/113070/qt-code-of-conduct

QT beginner using QPainter with a custom widget



  • Hi,

    I'm currently using a custom Widget and trying to draw an image on to the canvas, but I can't currently do so, I've tried re-implementing the mouseEvent method, but currently nothing works. The +16 is for the size of the picture I'm testing with.

    Thanks

    #include "canvas.h"
    
    Canvas::Canvas()
    {
        setMinimumSize(1280,800);
        QPalette pal = palette();
    
        // set black background
        pal.setColor(QPalette::Background, Qt::white);
        setAutoFillBackground(true);
        setPalette(pal);
    }
    
    void Canvas::mouseClickEvent(QMouseEvent *event)
    {
    
        if (event->button() == Qt::LeftButton) {
             lastPoint = event->pos();
             drawELement(event->pos());
    
            }
    }
    
    void Canvas::paintEvent(QPaintEvent *event)
    {
        QPainter painter(this);
        QImage *image = new QImage(":/graphics/graphics/straightH.png");
    
        //painter.drawImage(Qpo,*image);
    }
    
    void Canvas::drawELement(QPoint place)
    {
        QPainter painter(this);
        QImage *image = new QImage(":/graphics/graphics/straightH.png");
        painter.drawImage(place.x(),place.y(),*image);
        modified = true;
    
        update(place.x(),place.y(),place.x()+16,place.y()+16);
    
    }
    
    

  • Lifetime Qt Champion

    @jkwok678 said in QT beginner using QPainter with a custom widget:

    Also does QPainter store what's been drawn on the screen

    It is explained in the documentation: https://doc.qt.io/qt-5/qwidget.html#paintEvent
    "When the paint event occurs, the update region has normally been erased, so you are painting on the widget's background."

    You should optimise this:

    painter.drawImage(finalX,finalY,QImage(":/graphics/graphics/straightH.png"));
    

    Creating new QImage from file on every paintEvent is expensive. Do it once and store QImage instance as class member.


  • Lifetime Qt Champion

    @jkwok678 Drawing is done inside paintEvent. So, in drawElements you only generate the image and store it as member variable in your class. Then move

    painter.drawImage(place.x(),place.y(),*image);
    

    to your paintEvent. You can store place as member variable as well.

    void Canvas::paintEvent(QPaintEvent *event)
    {
        QPainter painter(this);
        painter.drawImage(place, image);
    }
    
    


  • Am i able to call the paintEvent method in the mouseClickEvent?

    The functionality I want is for me to me able to add a new picture to the screen every time, a click is registered?


  • Lifetime Qt Champion

    @jkwok678 said in QT beginner using QPainter with a custom widget:

    Am i able to call the paintEvent method in the mouseClickEvent?

    There is no need for that (and you should not do so). Call update() instead it will trigger repaint.



  • I've gotten rid of that stuff, but now, it only draws when the Canvas is created, in the top left corner. Is this a case where I need signal and slot?As I want to draw an image everytime I click on a spot.

    #include "canvas.h"
    
    Canvas::Canvas()
    {
        setMinimumSize(1280,800);
        QPalette pal = palette();
    
        // set black background
        pal.setColor(QPalette::Background, Qt::white);
        setAutoFillBackground(true);
        setPalette(pal);
    }
    
    void Canvas::mouseClickEvent(QMouseEvent *event)
    {
    
        if (event->button() == Qt::LeftButton) {
             lastPoint = event->pos();
             update();
    
    
    
            }
    }
    
    void Canvas::paintEvent(QPaintEvent *event)
    {
        QPainter painter(this);
        QImage *image = new QImage(":/graphics/graphics/straightH.png");
        painter.drawImage(lastPoint,*image);
        //painter.drawImage(Qpo,*image);
    }
    
    

  • Lifetime Qt Champion

    Hi,

    There's no mouseClickEvent. You likely want to use mousePressEvent.

    Note that you are currently leaking images a lot. Don't create them in the heap, there's no reason for that. And since you are using only one image, allocate it once in the constructor and re-use it in the paint event.



  • This post is deleted!


  • So, I feel like I've made a few changes, but when clicking right next to an existing image, it currently deletes, one that is already there. I've used 16 for the size of the image right now. But I was wondering if it's maybe too precise. Because the image is 16x16 pixels and I've used update 16, so should it really be 15, instead?

    #include "canvas.h"
    
    Canvas::Canvas()
    {
        setMinimumSize(1280,800);
        QPalette pal = palette();
        imageSize=16;
        // set black background
        pal.setColor(QPalette::Background, Qt::white);
        straightHImage = new QImage(":/graphics/graphics/straightH.png");
        setAutoFillBackground(true);
        setPalette(pal);
    }
    
    void Canvas::mousePressEvent(QMouseEvent *event)
    {
    
        if (event->button() == Qt::LeftButton) {
             lastPoint = event->pos();
             exactX = event->pos().x();
             exactY = event->pos().y();
             extraX = exactX%16;
             extraY = exactY%16;
             finalX = exactX - extraX;
             finalY = exactY - extraY;
             boundX = finalX+imageSize;
             boundY = finalY+imageSize;
             update(finalX,finalY,boundX,boundY);
    
    
            }
    }
    
    void Canvas::paintEvent(QPaintEvent *event)
    {
        QPainter painter(this);
        painter.drawImage(finalX,finalY,*straightHImage);
    
    }
    
    
    

  • Lifetime Qt Champion

    As I already wrote: there's no need to allocate your QImage on the heap.

    As for your issu, one simple way is to keep a list of points and repaint the image for each of them.



  • @SGaist said in QT beginner using QPainter with a custom widget:

    Hi,

    There's no mouseClickEvent. You likely want to use mousePressEvent.

    Use the "override" keyword in the header file when you want to re-implement a base class function. It will help you catch errors like this one.



  • @SGaist
    So, like this?
    Also does QPainter store what's been drawn on the screen or is it like JavaFX canvas, where it is more of a draw it then forget about it, as in the canvas doesn't know store what's drawn on the screen after. My reason for this question, is that I realised sometimes when I click adjacent to the existing images, sometimes those disappear, when that happens, does that still take memory?

    #include "canvas.h"
    
    Canvas::Canvas()
    {
        setMinimumSize(1280,800);
        QPalette pal = palette();
        imageSize=16;
        // set black background
        pal.setColor(QPalette::Background, Qt::white);
    
        setAutoFillBackground(true);
        setPalette(pal);
    }
    
    void Canvas::mousePressEvent(QMouseEvent *event)
    {
    
        if (event->button() == Qt::LeftButton) {
             lastPoint = event->pos();
             exactX = event->pos().x();
             exactY = event->pos().y();
             extraX = exactX%16;
             extraY = exactY%16;
             finalX = exactX - extraX;
             finalY = exactY - extraY;
             boundX = finalX+imageSize;
             boundY = finalY+imageSize;
             update(finalX,finalY,boundX,boundY);
    
    
            }
    }
    
    void Canvas::paintEvent(QPaintEvent *event)
    {
        QPainter painter(this);
        painter.drawImage(finalX,finalY,QImage(":/graphics/graphics/straightH.png"));
    
    }
    

  • Lifetime Qt Champion

    @jkwok678 said in QT beginner using QPainter with a custom widget:

    Also does QPainter store what's been drawn on the screen

    It is explained in the documentation: https://doc.qt.io/qt-5/qwidget.html#paintEvent
    "When the paint event occurs, the update region has normally been erased, so you are painting on the widget's background."

    You should optimise this:

    painter.drawImage(finalX,finalY,QImage(":/graphics/graphics/straightH.png"));
    

    Creating new QImage from file on every paintEvent is expensive. Do it once and store QImage instance as class member.


Log in to reply