PDA

View Full Version : How to solve this problem about drawImage() and paintEvent()?



Nicho
12th November 2013, 03:20
Hi, all
I am working under linux with QT4.7, and my test code is like below:


12 void MyWidget :: paintEvent ( QPaintEvent * event )
13 {
14 init();
15 }
16
17 void MyWidget :: init()
18 {
19 QImage bg( width(), height(), QImage::Format_ARGB32_Premultiplied );
20 QImage a( width(), height(), QImage::Format_ARGB32_Premultiplied );
21 QImage b( width(), height(), QImage::Format_ARGB32_Premultiplied );
22
23 QPainter p;
24
25 p.begin( &bg );
26 QRect r = rect();
27 p.fillRect( r, Qt::white );
28 p.end();
29
30 p.begin( &a );
31 p.setPen( QPen( QColor( Qt::red ), 5 ) );
32 p.drawLine( 10, 10, 50, 50 );
33 p.end();
34
35 p.begin( &b );
36 p.setPen( QPen( QColor( Qt::green ), 5 ) );
37 p.drawLine( 10, 70, 50, 10 );
38 p.end();
39
40 p.begin( this );
41 p.drawImage( QPoint(0,0), bg );
42 p.drawImage( QPoint(0,0), a );
43 p.drawImage( QPoint(0,0), b );
44 p.end();
45 }


Then, at the beginning the widget is shown correctly - there are two lines cross with each other at the Top-Left corner, one is green and another is red. But when I drag the Bottom-Right corner of this widget to resize it, the two lines will be repainted in a wrong way. Why and how to solve it?

Any suggestion is appreciated.

Nicho

anda_skoa
12th November 2013, 12:11
How are they painted incorrectly?
I.e. what are you expecting to see?

Btw, you can draw directly onto the widget in paintEvent(), i.e. create a QPainter on "this";

Cheers,
_

Nicho
12th November 2013, 13:53
How are they painted incorrectly?
I.e. what are you expecting to see?

Btw, you can draw directly onto the widget in paintEvent(), i.e. create a QPainter on "this";

Cheers,
_

anda_skoa,
I do not know why, but I failed to upload the pictures which may express my problem more clearly. so, would you do me a favour?Just use my code and show MyWidget directly in the main function, and try to resize the widget by mouse. If you see the two lines not being repained as they are defined, that is my problem. Thanks so much.

To paint with drawImage is because I want to do some test about image layer management.

Nicho

anda_skoa
12th November 2013, 16:45
Just use my code and show MyWidget directly in the main function, and try to resize the widget by mouse. If you see the two lines not being repained as they are defined, that is my problem. Thanks so much.


Maybe you should provide the code then. At least something that can be copied into an editor. You current code is incomplete and has "line numbers" mixed with the actual code.

Cheers,
_

ChrisW67
12th November 2013, 23:11
Here is a complete example:


#include <QApplication>
#include <QWidget>
#include <QImage>
#include <QPainter>

class MyWidget: public QWidget {
Q_OBJECT
public:
MyWidget(QWidget *p = 0): QWidget(p) {
}
protected:
void paintEvent ( QPaintEvent * event );
private:
void init();
};

void MyWidget :: paintEvent ( QPaintEvent * event )
{
init();
}

void MyWidget :: init()
{
QImage bg( width(), height(), QImage::Format_ARGB32_Premultiplied );
QImage a( width(), height(), QImage::Format_ARGB32_Premultiplied );
QImage b( width(), height(), QImage::Format_ARGB32_Premultiplied );

QPainter p;

p.begin( &bg );
QRect r = rect();
p.fillRect( r, Qt::white );
p.end();

p.begin( &a );
p.setPen( QPen( QColor( Qt::red ), 5 ) );
p.drawLine( 10, 10, 50, 50 );
p.end();

p.begin( &b );
p.setPen( QPen( QColor( Qt::green ), 5 ) );
p.drawLine( 10, 70, 50, 10 );
p.end();

p.begin( this );
p.drawImage( QPoint(0,0), bg );
p.drawImage( QPoint(0,0), a );
p.drawImage( QPoint(0,0), b );
p.end();
}

int main(int argc, char **argv)
{
QApplication app(argc, argv);
MyWidget w;
w.show();
return app.exec();
}
#include "main.moc"

The widget does indeed get garbled as you resize the window. When you create a QImage as you have done it is not initialised (as clearly stated in the docs). You fill the background image with white but leave the others with whatever random rubbish they started with. On top of the random rubbish you draw a line, then draw the combined result over the white background image. It's dumb luck if the images start out clear of rubbish (possibly because the memory is zeroed when first allocated to the process by the OS). In my case, each time through the paintEvent() the images are put in slightly different memory locations that overlapped their previous position so recognisable ghosts of former images are visible.

Does seem a long-winded way to do this:


class TypicalWidget: public QWidget {
Q_OBJECT
public:
TypicalWidget(QWidget *p = 0): QWidget(p) {
}
protected:
void paintEvent ( QPaintEvent * event ) {
QPainter p(this);
p.fillRect(rect(), Qt::white);
p.setPen( QPen( QColor( Qt::red ), 5 ) );
p.drawLine( 10, 10, 50, 50 );
p.setPen( QPen( QColor( Qt::green ), 5 ) );
p.drawLine( 10, 70, 50, 10 );
}
};

but you might have a reason.

Nicho
13th November 2013, 02:54
ChrisW67,
Thank you for your reply in detail.
I guessed the QImage would be initialized as transparency, so I leaved them as not filled.
I have re-read the docs, and here is the important information :
Warning: This will create a QImage with uninitialized data. Call fill() to fill the image with an appropriate pixel value before drawing onto it with QPainter.
I think I got what I should do now.
Thank you again.

Nicho