views:

295

answers:

2

i'm studying and modifying the fridge magnets example, and the last thing I've tried to do was to draw a few labels and lines that are supposed to be on the background.

After looking around trying to figure out how to draw the labels and lines, I learned that I could override QWidget's paintEvent() to do it. After I did it though, the application got laggy, and I found out that it was because paintEvent() was being called in a seemingly infinite loop.

Trying to figure out how to fix that, I moved the code that drew the labels and lines to the constructor of the class. Only the labels were drawn on the application though. After that, I left the labels in the constructor, but moved the code that drew the lines back to paintEvent(). It worked, the lines were drawn as expected, and paintEvent() was called only when dragging stuff around.

Why were the lines not being drawn on the constructor, and why paintEvent() got into an infinite loop?

Here's the snippet that's supposed to draw the labels and lines:

QPen pen(Qt::lightGray, 0, Qt::SolidLine, Qt::SquareCap, Qt::RoundJoin);
QPainter paint(this);
paint.setPen(pen);
int scale = 20;
for(int x=0; x<25; x++){
    QString timetext= "0"+QString::number(x)+":00";
    QLabel *time= new QLabel(timetext,this);
    time->move(x*scale,2);
    time->show();
    paint.drawLine(x*scale,12,x*scale,400);
}
+8  A: 

You are adding Objects to the Widget Tree during paintEvent(). That is deemed to fail. The Qt scheduler for damage&drawing will see that a new child has to be drawn and try to manage that and likely the loop is the result. If you override paintEvent(), do all the painting in the same object! Golden rule: paintEvent() is only for painting! Not for creating objects or anything else.

Do it like this:

QFont font(painter.font());
font.setBold(true);
painter.setFont(font);
painter.fillRect(rect(), Qt::black);
painter.setPen(Qt::white);
painter.drawText(rect(), Qt::AlignCenter, tr("White text on dark background. Awesome."));
ypnos
Should I move all the drawing code out of the constructor and into the paintEvent?
David McDavidson
Yes, drawing should only be done in paintEvent(). Or you could draw into a QPixmap that is background of a Widget (most times QLabel). Then you would only draw once (in a while), not touching paintEvent() itself. It depends on your application. Note that (re-)doing drawing work in paintEvent() is not as costy as one might think. In most cases, Qt uses double buffering, so simply moving windows around won't result in a paintEvent(). On the other hand, for example on remote sessions double buffering is not in effect.
ypnos
+2  A: 

Hey,

Why were the lines not being drawn on the constructor ?

I think they were, but they were "erased" by the next call to paintEvent() in which you didn't draw the lines anymore...

Why paintEvent() got into an infinite loop?

I think it could be related to your time->show(); which is called 25 times everytime paintEvent is called... I'm not sure about that but, since time as the widget as parent, when you call "show", maybe it calls "show" on its parent, therefore triggering paintEvent.... You know what I mean...

Since, Ypnos gave you a solution, I refer to him :)

Andy M