9
votes

This is my first time using Qt and I have to make a MSPaint equivalent with Qt. I am however having trouble with painting my lines. I can currently draw a line by clicking somewhere on the screen and releasing somewhere else, however when I draw a second line the previous line is erased. How could I keep the previously painted items when painting another item?

void Canvas::paintEvent(QPaintEvent *pe){
    QWidget::paintEvent(pe);
    QPainter p(this);
    p.drawPicture(0,0,pic);
}

void Canvas::mousePressEvent(QMouseEvent *mp){
    start = mp->pos();
}

void Canvas::mouseReleaseEvent(QMouseEvent *mr){
    end = mr->pos();
    addline();
}

void Canvas::addline()Q_DECL_OVERRIDE{
    QPainter p(&pic);
    p.drawLine(start,end);
    p.end();
    this->update();
}

Canvas is a class that derives QWidget, it has 2 QPoint attributes start and end.

Class body:

class Canvas : public QWidget{
Q_OBJECT
private:
    QPoint start;
    QPoint end;
    QPicture pic;
public:
    Canvas(){paint = false;setAttribute(Qt::WA_StaticContents);}
    void addline();
protected:
    void paintEvent(QPaintEvent *);
    void  mousePressEvent( QMouseEvent * );
    //void  mouseMoveEvent( QMouseEvent * );
    void  mouseReleaseEvent( QMouseEvent * );

};
1
I think the problem is that you're creating a new QPainter variable each time you add a new line which causes the previous QPainter variable stored to be destroyed since it has left scope (but due to the nature of OpenGL, it's kept in the framebuffer anyway). Try having QPainter a class-scope variable and see if that helps.Poriferous
@Poriferous - it doesn't matter, pic is his buffer, the painter should not affect the buffer data. This doesn't mean keeping the painter is a bad idea.dtech
@anaBad - what is pic? Show us the body of your widget class.dtech
pic would be QPaintDevice which is what QPainter isn't being drawn to. Hence my theory that it's a scope issue.Poriferous
@Poriferous - but from his code it seems like pic has class scope. It should persist between different calls. From the code posted so far I see nothing that would clear pic.dtech

1 Answers

6
votes

QPicture records QPainter commands. Also from its documentation you can read this:

Note that the list of painter commands is reset on each call to the QPainter::begin() function.

And the QPainter constructor with a paint device does call begin(). So each time the old recorded commands are deleted.

It may sound tempting to use it, since it does say a few good things, for example, that it is resolution independent, but this is not how drawing applications work in reality. Switch to a QPixmap and your drawings will persist.

Also, don't forget to initialize the pixmap, because by default it will be empty and you will not be able to draw on it.

Canvas() : pic(width,height) {...}

Furthermore, if you would like the introduce the concept of brushes as in artistic brushes and not QBrush, you might want to look at this approach to draw the line.

EDIT: Note that you should be able to prevent QPicture from losing its content by not calling begin() on it more than once. If you create a painter, dedicated to only drawing on it at class scope, and call begin in the constructor, different recorded drawing operations should persist. But as their number increases it will take more and more time to draw the QPicture to your widget. You could come around that by using both a QPicture and a QPixmap, and draw to both, use the picture to record the actions and the pixmap to avoid continuously redrawing the picture, even though you will do double the work it will still be more efficient, while you still retain the possibility to use the picture to re-rasterize in a different resolution or save the drawing history. But I doubt QPicture will do well as your drawing application begins to take shape of an actual drawing application, for example when you start using pixmap brushe stencils and such.