Seub
Seub

Reputation: 3192

C++/Qt : change (the size of) a QImage that is being painted

I apologize if I give more details than necessary. I have a class Canvas that looks like this:

class Canvas : public QWidget
{
    Q_OBJECT
public:
    explicit Canvas(int width = 700, int height = 700, QWidget *parent = 0);
    void setDelegate(CanvasDelegate *delegate);
private:
    CanvasDelegate *delegate;
    void paintEvent(QPaintEvent *event);
    void resizeEvent(QResizeEvent *resizeEvent);
    [...]
};

The Canvas::paintEvent(QPaintEvent *) function is implemented like this:

void Canvas::paintEvent(QPaintEvent *)
{
    delegate->redrawBuffer();
    QPainter canvas_painter(this);
    canvas_painter.drawImage(0, 0, *(delegate->getImage()));
}

And so the class CanvasDelegate looks like this:

class CanvasDelegate
{
    friend class Canvas;

public:
    CanvasDelegate(const Canvas *canvas);
    ~CanvasDelegate();

    const QImage * getImage() const;

    void drawPoint(const Complex &z, const QColor &color = "black", int width = 3);
    [...]
    virtual void redrawBuffer(const H2Isometry &mobius = H2Isometry::identity()) = 0;
    virtual void mousePress(QMouseEvent * mouseEvent) = 0;
    [...]


protected:
    const Canvas *canvas;

    int sizeX, sizeY;
    [...]

    QPen *pen;
    QImage *image;
    QPainter *painter;

    void rescale(int sizeX, int sizeY);
};

The constructor of CanvasDelegate is as follows:

CanvasDelegate::CanvasDelegate(const Canvas *canvas) : canvas(canvas)
{
    pen = new QPen;
    image = new QImage(canvas->width(), canvas->height(), QImage::Format_RGB32);
    painter = new QPainter(image);
    [...]
}

I'm not sure this is the best design ever but this is not my question (any comments are welcome, though). My problem is what happens when the window (Canvas) is resized. Here is what my code looks like:

void Canvas::resizeEvent(QResizeEvent *resizeEvent)
{
    QSize newSize = resizeEvent->size();
    delegate->rescale(newSize.width(), newSize.height());
    //update();
}


void CanvasDelegate::rescale(int sizeX, int sizeY)
{
    *image = QImage(sizeX, sizeY, QImage::Format_RGB32);
    painter->eraseRect(0, 0, sizeX, sizeY);

    this->sizeX = sizeX;
    this->sizeY = sizeY;
    [...]
}

The problem is that when I run the program, it crashes. Apparently there is a segmentation fault when painter->eraseRect(0, 0, sizeX, sizeY); is called in void CanvasDelegate::rescale(int sizeX, int sizeY). I don't understand why, I don't see what the problem is.

In a previous version, I had written the following (which now seems to me more complicated than necessary):

void CanvasDelegate::rescale(int sizeX, int sizeY)
{
    QImage * oldImage = image;
    QImage * newImage = new QImage(sizeX, sizeY, QImage::Format_RGB32);

    QPainter * oldPainter = painter;
    QPainter * newPainter = new QPainter(newImage);
    newPainter->eraseRect(0, 0, sizeX, sizeY);
    newPainter->setPen(*pen);

    image = newImage;
    painter = newPainter;

    delete oldImage;
    delete oldPainter;

    this->sizeX = sizeX;
    this->sizeY = sizeY;
    [...]
}

But that does not work: I get a Qt error QPaintDevice: Cannot destroy paint device that is being painted. If I remove delete oldImage; and delete oldPainter;, everything works fine but that is a disgusting memory leak, isn't it.

Does someone understand why what I have written does not work, and what I need to do?

Thank you very much for your attention.

Upvotes: 2

Views: 3469

Answers (1)

Boris Dalstein
Boris Dalstein

Reputation: 7748

I'm not exactly sure why painter->eraseRect(0, 0, sizeX, sizeY); segfaults, but it may be that when the paintdevice of a QPainter is an image, its size shoudn't change, and therefore *image = QImage(sizeX, sizeY, QImage::Format_RGB32); breaks this assumption.

Therefore, I would try, before resizing the image, to delete the QPainter, then resize the image, then allocate a new QPainter. In code:

void CanvasDelegate::rescale(int sizeX, int sizeY)
{
    delete painter;
    *image = QImage(sizeX, sizeY, QImage::Format_RGB32);
    painter = new QPainter(image);
    painter->eraseRect(0, 0, sizeX, sizeY);
    painter->setPen(*pen);

    this->sizeX = sizeX;
    this->sizeY = sizeY;
    [...]
}

Upvotes: 1

Related Questions