PDA

View Full Version : Not updating while painting in QMdiArea



rippa
9th April 2008, 15:44
Hello All.

My task is to connect to MDI sub windows with a line. Im calculating coordinates of my windows, save them and then drawing a line in the QMdiArea->viewport() using QPainter in reimplementation of paintEvent.
The problem is Qt repaints only those parts of QMdiArea that are under my child windows, and i need whole viewport to be repainted to update my line as well when moving child windows i.e. QPaintEvent->rect() = my child form size and position, not viewport()->rect().

So how do i force Qt to repaint whole viewport how it is done in simple widgets instead of child windows parts?

Thanks in advance.

wysota
9th April 2008, 16:23
paintEvent() of which object do you reimplement?

rippa
9th April 2008, 18:35
1. I made a class
MyQMA: public QMdiArea
{
...
protected:
void paintEvent(QPaintEvent* pe)
{
QPainter p(this->viewport());
p.drawLine(QPoint(X1,Y1),QPoint(X2,Y2)); //X1,Y1,X2,Y2 - sub windows coords
}
...
}

2. And within this paintEvent pe->rect() = MyQMA->rect() only if mouse pressed and moved within the MDI. But if i move child window or take some other window over my application pe->rect() = MySubwindow->rect(). And connecting line is painted correctly only if i press and move mouse, not if i move child MDI subwindow. :confused:

wysota
9th April 2008, 18:47
I guess the best solution is to apply an event filter on all sub windows, so that you are notified when they get moved. Then you can update() the mdi area's viewport which should trigger the paintEvent properly.

rippa
9th April 2008, 18:59
So it isnt possible to force QMdiArea::paintEvent() to update whole area whenever QMdiArea::paintEvent() called?

And the solution is to implement new MDI widget that inherits QWidget by myself
Or to call update() in all events like moving windows, adding new windows, deleting old etc?

wysota
9th April 2008, 19:28
So it isnt possible to force QMdiArea::paintEvent() to update whole area whenever QMdiArea::paintEvent() called?
I think the problem is that the paint event is not called at all, not that it is called with wrong parameters. At least that's what I understood from what you have written.


And the solution is to implement new MDI widget that inherits QWidget by myself
Or to call update() in all events like moving windows, adding new windows, deleting old etc?

As I said, installing an event filter and manually triggering update() should be enough. There is no need to reinvent the wheel.

rippa
9th April 2008, 19:42
I think the problem is that the paint event is not called at all, not that it is called with wrong parameters. At least that's what I understood from what you have written.

Its surely called Both times.
It is called when i move child window and it is called when i press/move mouse in the mdi area. I cout << pe->rect << both times and see that second time it updates whole MDI window, but first time it updates only area under my moving sub window.



As I said, installing an event filter and manually triggering update() should be enough. There is no need to reinvent the wheel.

Yes, i thought about this solution but its not so convinient because MDI need to be updated not only when subWindows move but in some different cases. And paintEvent() is actually CALLED when windows move so it wont help i think, but ill try. Thanks anyway.

I thought there must be something like widget(paint engine) property that sets whether paintEvent should update whole widget or not. It would have been much easier and logical imho.
Or maybe overriding QPaintEvent* that passed to paintEvent() function, or something like that.

wysota
9th April 2008, 21:06
Its surely called Both times.
So why don't you ignore the rectangle and redraw everything you need?



Yes, i thought about this solution but its not so convinient because MDI need to be updated not only when subWindows move but in some different cases.
Why so? You get the event (which in turn has its type) as a parameter to the filter so there is no problem in reacting on wanted events only. Otherwise you'd probably fall into an infinite loop.



I thought there must be something like widget(paint engine) property that sets whether paintEvent should update whole widget or not. It would have been much easier and logical imho.
Why do you care about the rectangle so much? Painting is not clipped to the rectangle, is it? Even if it is, you can probably turn clipping off by passing some widget hint while constructing the widget.

rippa
9th April 2008, 21:49
So why don't you ignore the rectangle and redraw everything you need?

That is the question ) How do i repaint all?



Why do you care about the rectangle so much? Painting is not clipped to the rectangle, is it? Even if it is, you can probably turn clipping off by passing some widget hint while constructing the widget.

In this case while sub windows move painting IS clipped to the rectangle equal to moving subwindow. I think this is done by Qt to optimize painting, since generally there is no additional painting on mdi area besides child windows.
And that was the question what window hint or what property turns clipping off.



Why so? You get the event (which in turn has its type) as a parameter to the filter so there is no problem in reacting on wanted events only. Otherwise you'd probably fall into an infinite loop.


Yes you are right, but this is not the best solution i beleive because in this case painting will be doubled. 1st time from native child window move event (only clipped area) and second time from event filter.
Much nore logical would be reimplementation QMdiArea::paintEvent() so it updates whole widget or turning clipping off somehow.
And that is what i asked in 1st post ) HOW? :eek:

wysota
9th April 2008, 23:38
That is the question ) How do i repaint all?
Hmm... I don't understand the question... What do you mean "how"? Using QPainter and drawing in coordinates you want to redraw.


In this case while sub windows move painting IS clipped to the rectangle equal to moving subwindow. I think this is done by Qt to optimize painting, since generally there is no additional painting on mdi area besides child windows.
Clipping is certainly not an optimizing technique :) It's very expensive, so it's turned off in most situations programmers usually don't mess with. Are you sure the painter is clipped? The fact that the event carries a rectangle doesn't yet mean there is actually clipping involved.


And that was the question what window hint or what property turns clipping off.

Qt::WA_PaintUnclipped I guess...


Yes you are right, but this is not the best solution i beleive because in this case painting will be doubled.
Not necessarily. paintEvents are usually optimized, so there is a chance they'd get optimized here as well.


Much nore logical would be reimplementation QMdiArea::paintEvent()
Hmm... isn't it what you did?

rippa
10th April 2008, 07:24
Hmm... I don't understand the question... What do you mean "how"? Using QPainter and drawing in coordinates you want to redraw.

But how should i set these coordinates in paintEvent() function? I want to redraw all, but only small rect is redrawn. i cant call update(QRect) in it because it leads to infinite loop.



Clipping is certainly not an optimizing technique :) It's very expensive, so it's turned off in most situations programmers usually don't mess with. Are you sure the painter is clipped? The fact that the event carries a rectangle doesn't yet mean there is actually clipping involved.

I check QPaintEvent::rect() every time paintEvent() called. And its equal to small rectangle = child window. Doesnt that mean that painting is clipped?



Qt::WA_PaintUnclipped I guess...

0o, ill try that as soon as i get to work )
Edit: Tried, doesnt help =(

wysota
10th April 2008, 10:17
Doesnt that mean that painting is clipped?
No. It means you can optimize redrawing by changing only the marked rectangle.

rippa
10th April 2008, 11:21
Anyway.. Nothing helps. Even reimplementation of moveEvent() in my child window. Because Qt puts my child window on its own mdi sub window, which i cant inherit, and move mdi sub window so my child window receive moveEvent only once, when it is created.

wysota
10th April 2008, 16:09
But what exactly is your problem? If you are trying to obtain a paint event with a rectangle containing your whole viewport, then it won't happen and you don't need it. Simply redraw more than the rectangle in your paint event. If you want the whole viewport to be updated, install event filters and call update(void) on the viewport and you'll get a paint event containing the whole viewport if that's important for you.

rippa
10th April 2008, 18:52
Yes, i need to redraw whole viewport to make my line that connects two sub mdi windows display correctly. You are saying "Simply redraw more than the rectangle".. But how can i do this?? As i can see i cant decide what area to redraw !inside paintEvent()!, Qt decides that by passing QPaintEvent to my paintEvent function.
And for event filter i cant get move event from MdiSubWindow, as it is created when I do MyQMdiArea->addSubWindow(MySubWidget);. And there is no acces (signals) from this subwindow that i can catch.

wysota
10th April 2008, 20:46
As i can see i cant decide what area to redraw !inside paintEvent()!, Qt decides that by passing QPaintEvent to my paintEvent function.
That's not true. The rectangle given by the paint event is only a hint, nothing more.

Try this:

void MyClass::paintEvent(QPaintEvent *pe){
QMDIArea::paintEvent(pe);
QPainter p(viewport());
p.setPen(Qt::red);
p.drawLine(viewport()->rect().topLeft(), viewport()->rect().bottomRight());
p.setPen(Qt::blue);
p.drawLine(pe->rect().topLeft(), pe->rect().bottomRight());
}

rippa
14th April 2008, 15:00
That's not true. The rectangle given by the paint event is only a hint, nothing more.


It seems to me that you dont understand what im talking about..
Please, be good, download simple test project ive attached. Try to move sub windows and u will see what i mean.

wysota
14th April 2008, 16:02
I corrected some of the side mistakes you made and your app was suffering from as well.

rippa
14th April 2008, 17:35
Thank you very much. You really helped me. :)