PDA

View Full Version : spectrogram with rescaler in mdi subwindow



dusan
27th February 2011, 21:19
Hello,

I am trying to implement an application in which central widget of the main window is
a MDI area in which I create a subwindow with a spectrogram plot. The issue I have is that
if the spectrogram has a rescaler (in order to preserve aspect ratio) replotting/refreshing
of the sub window does not work correctly.

To illustrate the problem I'm seeing in my application I have modified spectrogram example
by adding MDI area as a central widget to the main window. After clicking "Increase size"
button only the area that was previously occupied by the window is repainted. Please see
attached picture. Also if I create two sub windows side by side and the increase the size
of the first one so that it overlaps the second one, then after decreasing the size of the first
window the second one is not refreshed. (see the third picture).

I will appreciate if somebody can try to reproduce this behavior and of course can suggest
solution.

Thanks,
Dusan

599459955996

5997

Uwe
28th February 2011, 07:30
Looks like a Qt bug - when increasing the canvas gets a paint event for the previous region only. But even if the canvas ignores the region and does a full repaint, the new area gets not painted.

As workaround you can add an update manually for the canvas to your increase method:


void MainWindow::increase()
{
...
activeSubWindow->setGeometry(rect);
m_plot->canvas()->update();
}Uwe

dusan
28th February 2011, 13:13
Thank you for offering solution. It definitely helps with refreshing in case the size
of the window is changed from within the (increase) function, but it still does not gets
repainted if I resize the window by dragging the border of the window itself.

The other issue that remains is that the second window is not refreshed once
I decrease the size of the first one, as it is shown in picture 3 in my original post.
I guess I'll need to explicitly call canvas()->update() once the window receives
a signal that some of it's area need refreshing. Can you advice on that.
(in which subwindow slot should I add canvas()->update().)

And the third observation is that if I remove d_rescaler from the Plot
refreshing woks just fine. Is there a chance to have some kind of workaround
somewhere in the rescaler code that will fix this. If this is a Qt bug, how Plot
without rescaler repaints the whole area, while the Plot with rescaler does not?

Thanks again for your help.
Dusan

dusan
28th February 2011, 20:42
Hello,

I did some further debugging by inserting debug statements to trace the propagation of events and here is what I've found.

The sequence of events in case "repaint( contentsRect() );" is called from QwtPlotCanvas::replot() (original code)
is:

MainWindow::increase()
Plot(0x987ccc8) QResizeEvent(0xbf803078)
Plot(0x987ccc8) QEvent(0x989c5d0, type = 76)
Plot(0x989aa70) QPaintEvent(0xbf80079c)
Plot(0x987ccc8) QPaintEvent(0xbf80091c)
end of MainWindow::increase()
Plot(0x987ccc8) QPaintEvent(0xbf803b5c)
MainWindow::decrease()
Plot(0x987ccc8) QResizeEvent(0xbf803078)
Plot(0x987ccc8) QEvent(0x9889638, type = 76)
Plot(0x987ccc8) QPaintEvent(0xbf80091c)
end of MainWindow::decrease()

as you can see after clicking decrease button the paint event is called only for one subwindow(plot) (0x987ccc8).
The other window which has been obscured partially by the first one does not receive the paint event. Also only the
portion of the first window that covers the area of the previous size of the window is repainted after clicking the increase
button.

If I change "repaint( contentsRect() );" to "update ( contentsRect() );" in QwtPlotCanvas::replot()
the sequence of events is:

MainWindow::increase()
Plot(0x8b59448) QResizeEvent(0xbfe09c28)
Plot(0x8b59448) QEvent(0x8b6e318, type = 76)
end of MainWindow::increase()
Plot(0x8b59448) QPaintEvent(0xbfe09ddc)
MainWindow::decrease()
Plot(0x8b59448) QResizeEvent(0xbfe09c28)
Plot(0x8b59448) QEvent(0x8b54e80, type = 76)
end of MainWindow::decrease()
Plot(0x8b4e2f0) QPaintEvent(0xbfe09c5c)
Plot(0x8b59448) QPaintEvent(0xbfe09ddc)

and in this case after clicking the decrease button both subwindows(plots) (0x8b59448 and 0x8b4e2f0) receive QPaintEvent.

So for some reason invoking repaint from QwtPlotCanvas::replot() prevents the paint event to be sent to all
subwindows in the mdi area that need to be refreshed. Changing it to update somehow solves the problem by correctly
sending QPaintEvent to all subwindows.

Whether this is a Qt bug I do not know, but that's what I've found experimenting with the code.

Dusan

6001 6002

Uwe
1st March 2011, 09:39
QwtPlotRescaler installs an event filter catching resize events for the canvas and itsself triggers repaints ( via QwtPlot::replot() ) for the canvas. Obviously Qt is not able to handle repaints inside of resize events in your MDI situation ( when using update() the paint event is processed later, when the application has left processing of the resize event ).

It depends on the situation of the application if it is better to have an immediate repaint of the canvas or you want wait and collect consecutive updates and to repaint asynchronously after some delay. But I guess using update is the better solution for most applications.

So I have introcuced a new flag QwtPlotCanvas::ImmediatePaint, that controls whether QwtPlotCanvas::replot() calls repaint or update. The default setting is off, so update() is used.

Regardless how the flag is set QwtPlotRescaler temporarily disables QwtPlotCanvas::ImmediatePaint as it never makes sense to use repaint instead of update for this situation. But I guess the right solution here is neither update() nor repaint() as there will always be a following paint event because of the initial resize event. I will check this.

But for your problem the current code in SVN trunk should be fine - using QwtPlot::updateAxes() instead of QwtPlot::replot() in QwtPlotRescaler::rescale() is an optimization only.

Uwe

dusan
1st March 2011, 14:39
Thank you for making this change.
Can you give us an example where ImmediatePaint might be beneficial, since by default it is turned off.

Dusan