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

drawing shapes onto QPixmap with QPaintEvent



  • I am trying to draw shapes onto a pixmap, but both need to be viewed in a QGraphicsView.
    Currently the pixmap is loaded into the view, but when I press my mouse it won't add any points onto the pixmap. It does register the points perfectly, but I would like them to be visual.
    Is there anyone who can help me with this?

    Thanks

    #include "graphicsview.h"
    
    GraphicsView::GraphicsView(QWidget *parent) : QGraphicsView(parent)
    {
        scene = new QGraphicsScene();
        this->setScene(scene);
        this->setAlignment(Qt::AlignLeft | Qt::AlignTop);
        LoadImage();
    }
    
    void GraphicsView::mousePressEvent(QMouseEvent *event)
    {
        if(event->button() == Qt::LeftButton)
        {
            QPointF point = mapToScene(event->pos());
            double x = point.x();
            double y = point.y();
            qv_points << QPointF(x,y);
        }
        this->update();
    
    }
    
    void GraphicsView::paintEvent(QPaintEvent* event)
    {
        QPainter painter(viewport());
        painter.drawPixmap(event->rect(), pixmap);
        painter.setPen(QPen(Qt::green, 5));
        painter.setBrush(QBrush(Qt::green, Qt::CrossPattern));
    
        QPolygonF polygon;
        polygon << qv_points;
        painter.drawPolygon(polygon);
    
        painter.drawPoints(qv_points);
    }
    
    void GraphicsView::LoadImage()
    {
        QString filename = QFileDialog::getOpenFileName(this, tr("Open Image"), QDir::currentPath(), tr("Image Files (*.png *.jpg *.jpeg)"));
        pixmap = QPixmap(filename);
    
        QRectF sceneRect = this->sceneRect();
        pixmap.scaled (sceneRect.width (),sceneRect.height (), Qt::KeepAspectRatio, Qt::SmoothTransformation);
    }
    


  • is there anyone who can help me?


  • Lifetime Qt Champion

    Hi
    Please allow 24 hours to get replies. The users here are in different time zones and
    comes online at various times.

    Regarding your issues.
    Did you inspect the point values and see they are actually inside the pixmap/seems valid.
    If it paints the pixmap and u can see it, the points should also draw.



  • @mrjj said in drawing shapes onto QPixmap with QPaintEvent:

    Did you inspect the point values and see they are actually inside the pixmap/seems valid.
    If it paints the pixmap and u can see it, the points should also draw.

    Yes, that's also what I thought. They seem to be valid (checked with debugger), but somehow the points won't show up. It's not possible that the pixmap is drawn upon the drawn points, is it?


  • Lifetime Qt Champion

    @hobbyProgrammer
    Hi
    Well you draw the pixmap first so that is very unlikely.

    Is there a reason you draw directly on the View and not use
    https://doc.qt.io/qt-5/qgraphicspixmapitem.html
    for the pixmap ?

    I would try with some fixed values like from 0,0 100,100 200,200
    and see. ( in paintevent)

    I suspect its just something with coordinate system
    Since you call QPointF point = mapToScene(event->pos());
    the points are in scene coordinates but i wonder if that will match
    the views coordinates.



  • @mrjj So I did it with fixed Points and that seems to work. But it doesn't seem to call the paintEvent when I add the points on a mousePress. It gets called once and after that it never gets called anymore. This is my current code:

    #include "graphicsview.h"
    
    GraphicsView::GraphicsView(QWidget *parent) : QGraphicsView(parent)
    {
        scene = new QGraphicsScene();
        this->setScene(scene);
        this->setAlignment(Qt::AlignLeft | Qt::AlignTop);
        LoadImage();
    }
    
    void GraphicsView::mousePressEvent(QMouseEvent *event)
    {
        if(event->button() == Qt::LeftButton)
        {
            qDebug() << "Pressed at" << mapToScene(event->pos());
            QPointF point = mapToScene(event->pos());
            double x = point.x();
            double y = point.y();
            qv_points << QPointF(x,y);
        }
        this->update();
    }
    
    void GraphicsView::paintEvent(QPaintEvent* event)
    {
        QPolygonF polygon;
        qDebug() << qv_points;
        polygon << qv_points;
    
        QPainter painter(viewport());
        painter.setPen(QPen(Qt::green, 5));
        painter.setBrush(QBrush(Qt::green, Qt::CrossPattern));
    
        QRect dirtyRect = event->rect();
        image = pixmap.toImage();
        painter.drawImage(dirtyRect, image, dirtyRect);
    
        painter.drawPolygon(polygon);
        this->update();
    }
    
    void GraphicsView::LoadImage()
    {
        QString filename = QFileDialog::getOpenFileName(this, tr("Open Image"), QDir::currentPath(), tr("Image Files (*.png *.jpg *.jpeg)"));
        pixmap = QPixmap(filename);
    
        QRectF sceneRect = this->sceneRect();
        pixmap.scaled (sceneRect.width (),sceneRect.height (), Qt::KeepAspectRatio, Qt::SmoothTransformation);
        QGraphicsPixmapItem pixmapItem(pixmap);
    }
    

    I added the line

    qDebug() << qv_points;
    

    and it doesn't seem to get there since I get no debug information from that. I only get the debug info from the mouse press event.


  • Lifetime Qt Champion

    @hobbyProgrammer

    Hi
    But if you see the pixmap then it clearly goes there ?



  • @mrjj yes, but it only seems to go there once. I see the pixmap and I see that it prints an empty QVector and it does that only once. When I press the mouse button it doesn't seem to update.


  • Lifetime Qt Champion

    @hobbyProgrammer
    Hi
    You call this->update();
    so it really should paint again.

    You could in paint event do
    void GraphicsView::paintEvent(QPaintEvent* event)
    {
    static int cc=0;
    qDebug() << "paintEvent cc=" << cc++;

    and see if count raises when you press mouse.



  • @mrjj I implemented the code that you said I should try, but it doesn't raise the cc.


  • Lifetime Qt Champion

    @hobbyProgrammer

    Ok. that i cannot guess.
    You can try with repaint() from mousePress.

    Also, in paintEvent
    this->update();
    Could cause infinite recursion so its not nice to call update from paintEvent



  • @mrjj I removed the update and added the repaint, but it still didn't resolve the issue.


  • Lifetime Qt Champion

    @hobbyProgrammer

    Ok. then i really cant guess.
    Code seems fine and should work.


  • Moderators

    @hobbyProgrammer
    I would suggest calling the base implementation of mousepressevent as well

    void GraphicsView::mousePressEvent(QMouseEvent *event)
    {
       QGraphicsView::mousePressEvent(event);
    
        if(event->button() == Qt::LeftButton)
        {
            QPointF point = mapToScene(event->pos());
            double x = point.x();
            double y = point.y();
            qv_points << QPointF(x,y);
        }
        this->update();
    
    }
    


  • @mrjj It does work when I put another app on the forground such as google chrome and leave the app on the background. When I put the app on the foreground, it updates the co√∂rdinates.

    @J-Hilk unfortunately, that does not resolve my issue



  • @mrjj is is perhaps better to use drawForeground and drawBackground for this issue, or wouldn't it matter?


  • Lifetime Qt Champion

    @hobbyProgrammer
    Hi
    well DrawForeground and DrawBackground is often used for Grid feature or
    similar. However, if you pixmap is sort of a background type, it would make sense but i cant promise it works better since i do not see why it would not
    call the paintEvent for the view. Or what it is you are seeing.

    Also since you do not seem to call QGraphicsView normal paint,
    i wonder if you dont use any of QGraphicsView features besides
    just drawing on it ?



  • @mrjj Hi,

    All the code I used, I posted here so if it's not in this part of the code, it's nowhere in the code.
    I'm going to try to recreate the project step by step, maybe I'll find the mistake.


  • Lifetime Qt Champion

    @hobbyProgrammer
    Hi
    Just to be sure i understand the actual task.
    You want to show an image and then draw points by clicking
    on the image. These points should be "live" meaning they should not be combined with image but drawn on top of the image ?

    Is it a requirement that the image can be zoomed and panned around and those points follow the scaling?



  • @mrjj yes exactly! but when I zoom in and out I would like there to be a scrollbar so that I can view and edit the entire image and not just the upper part.


  • Lifetime Qt Champion

    @hobbyProgrammer

    Well im asking as you use the GraphicsView in a (in my opinion) odd way
    as you treat it like the QWidget paint.
    Normally one would use
    https://doc.qt.io/qt-5/qgraphicspixmapitem.html
    for the image and and make a custom QGraphicsItem to handle the overlay points
    and in other ways used the features of the QGraphicsScene/view.

    Where are you seem to directly draw on the view as a normal Widget.

    Its not criticism! i just wondered if you needed all of the QGraphicsScene/view stuff as doing with just a QWidget and paint is far more simple if
    all the other features is not needed.

    And when you just overwrite paint for view (as the code you shown), then you are not using ANY of the selection/grouping/scaling etc of the Graphics Framework.
    So i had to ask :)



  • @mrjj okay, but I still don't get how to use the QGraphicsScene/View now.
    Do I make the ScrollArea a QGraphicsView and then load the QGraphicsPixmap into the QGraphicsView?

    I don't really get the structure that is needed for this.


  • Lifetime Qt Champion

    @hobbyProgrammer

    Hi
    Normally the one would use QGraphicsPixmapItem
    and maybe a custom item for the lines/polygon.
    You would not need a ScrollArea



  • @mrjj Okay so I tried to make a new graphicsview and this is the code.
    It doesn't seem to load the pixmap.
    It's probably a stupid mistake (I make them a lot), since I've wasted way too much time on this.

    #include "graphicsview.h"
    
    GraphicsView::GraphicsView(QWidget *parent)
        : QGraphicsView(parent)
    {
        scene = new QGraphicsScene(this);
        setScene(scene);
    }
    
    void GraphicsView::open()
    {
        filename = QFileDialog::getOpenFileName(this,tr("Open File"), QDir::currentPath(), tr("Image Files(*.png *.jpg *.jpeg)"));
        qDebug() << filename;
        QGraphicsPixmapItem *pixmap = scene->addPixmap(QPixmap(filename));
        update();
    }
    

Log in to reply