2 Attachment(s)
QwtLegend: different behaviour when inserting a legend after/before adding curves
I have an application that plots curves in a QwtPlot object. Now, I would like, at will, to show/hide the legend for that QwtPlot object. For this, I am doing something like:
Code:
void GraphPanelPlotWidget::setLegend(const bool &pLegend)
{
// Show/hide our legend
if (pLegend != legend())
}
As expected, it does create/destroy the legend as requested. However, here are two slightly different scenarios (through my application's GUI):
- I show the legend and then create and plot some curves; and
- I create and plot some curves and then show the legend.
I would expect both scenarios to yield the exact same result. Yet, although the first scenario gives me what I would expect, i.e.
Attachment 12678
The second scenario doesn't. Instead of the legend itself, I only have some blank space:
Attachment 12677
I had a look at the various Qwt examples, including the 'legends' one, and what I am doing in terms of showing/hiding (or, rather, inserting/removing) the legend is no different. So, why am I getting a different behaviour for my two scenarios, not least since in the 'legends', we may have some curves and no legend, and then decide to show the legend and it will indeed show it right, but... not in my case...!? I am clearly missing something, but I can see what it is.
Thanks in advance to anyone who can help me with this...
Re: QwtLegend: different behaviour when inserting a legend after/before adding curves
Guess GraphPanelPlotWidget is some sort of container - not the plot widget. Then what happens when doing:
Code:
insertLegend
(pLegend?
new QwtLegend(nullptr
):0);
Uwe
Re: QwtLegend: different behaviour when inserting a legend after/before adding curves
Sorry, my bad. I should have made it clear that GraphPanelPlotWidget actually inherits from QwtPlot. Anyway, I thought I would still try your suggestion, but as expected it didn't make any difference (in fact, if I am not mistaken, it should now leak when 'hiding' the legend since its parent is not a QwtPlot object anymore).
Re: QwtLegend: different behaviour when inserting a legend after/before adding curves
Well then I would need to see a small compile demo to check what's going on.
Uwe
Re: QwtLegend: different behaviour when inserting a legend after/before adding curves
Well, that's the thing: I tried to generate a small example that reproduces my problem, but I to no avail. In fact, I am not surprised that I can't reproduce it since I believe the problem is most likely at my end. It's just that I have tried various things at my end and can't seem to fix it. So, I am, here, merely trying to get some further ideas for me to try...
Re: QwtLegend: different behaviour when inserting a legend after/before adding curves
Ok, I have found out why I am having the behaviour I described above. It has to do with my calling QWidget::setUpdatesEnabled() on my QwtPlot object. Indeed, I customise quite a few things in my QwtPlot object, so I thought I would temporarily prevent it from updating itself. In other words, I have something like this:
Code:
myPlot->setUpdatesEnabled(false);
...
myPlot->insertLegend
(addLegend?
new QwtLegend(myPlot
):0);
...
myPlot->setUpdatesEnabled(true);
This can easily be reproduced in the simpleplot example:
Code:
#include <qapplication.h>
#include <qwt_plot.h>
#include <qwt_plot_curve.h>
#include <qwt_plot_grid.h>
#include <qwt_symbol.h>
#include <qwt_legend.h>
int main( int argc, char **argv )
{
plot.setUpdatesEnabled(false);
plot.setTitle( "Plot Demo" );
plot.setCanvasBackground( Qt::white );
plot.
setAxisScale( QwtPlot::yLeft,
0.0,
10.0 );
grid->attach( &plot );
curve->setTitle( "Some Points" );
curve->setPen( Qt::blue, 4 ),
curve
->setRenderHint
( QwtPlotItem::RenderAntialiased,
true );
curve->setSymbol( symbol );
curve->setSamples( points );
curve->attach( &plot );
plot.setUpdatesEnabled(true);
plot.resize( 600, 400 );
plot.show();
return a.exec();
}
So, is that behaviour 'normal'? I mean, I would really like to be able to make calls to QWidget::setUpdatesEnabled() whenever I see fit, so how can I go about it without messing up my legend?
Re: QwtLegend: different behaviour when inserting a legend after/before adding curves
Ok, I have 'fixed' it. In the end, the 'problem' is with QwtLegendLabel::setData(). Indeed, it disables updates, but then only reenables them if it was originally enabling them. Now, because my application temporarily disable them at some point, QwtLegendLabel doesn't reenable updates, hence the 'blank' legend I mentioned in my original message.
To address this issue, I had to something like:
Code:
{
Q_OBJECT
public:
explicit MyLegend
(QWidget *pParent
) : {
}
protected:
virtual void updateWidget
(QWidget *pWidget,
const QwtLegendData &pLegendData)
{
QwtLegend::updateWidget(pWidget, pLegendData
);
pWidget->setUpdatesEnabled(true);
}
};
I wish I didn't have to do this, but at least my application is now working as expected.
Re: QwtLegend: different behaviour when inserting a legend after/before adding curves
On my box ( Linux/X11 Qt-5.9.1 ) disabling the updates of the plot leads to not painting anything at all - f.e the simpleplot example comes with an empty window frame.
But this is the expected behavior: if you explicitly disable automatic updates you have to call update manually and of course you need to know what to update.
But does disabling updates totally make sense in your case ? Usually only repainting of the canvas should be expensive and if you really have unwanted replots - triggered by update - it might be better to disable updates for the canvas only. Or maybe introducing your own flag, that could be handled in YourPlot::replot().
Uwe
Re: QwtLegend: different behaviour when inserting a legend after/before adding curves
Quote:
On my box ( Linux/X11 Qt-5.9.1 ) disabling the updates of the plot leads to not painting anything at all - f.e the simpleplot example comes with an empty window frame.
But this is the expected behavior: if you explicitly disable automatic updates you have to call update manually and of course you need to know what to update.
Note that in 'my' version of the simpleplot example, I reenable updates by calling setUpdatesEnabled(true) on the QwtPlot object, which results in update() being automatically called on the QwtPlot object. Thus, on Ubuntu 16.04 and with Qt 5.9.3, I am getting the expected result when it comes to the plot, just not the legend (which is 'blank').
Quote:
But does disabling updates totally make sense in your case ? Usually only repainting of the canvas should be expensive and if you really have unwanted replots - triggered by update - it might be better to disable updates for the canvas only. Or maybe introducing your own flag, that could be handled in YourPlot::replot().
I appreciate what you are saying, but there are two cases where I am currently calling setUpdatesEnabled():
- I need to customise a plot by modifying several of its properties (line, symbols, colours, etc.). Here, I agree that your approach would work.
- I need to customise a 'big' widget that can contain one or several plots (among other things). Because that widget is relatively 'heavy', I call setUpdatesEnabled() on it to disable updates, so that I can do my customisation. Once I am done with my customisation, I reenable updates on my 'big' widget. If I wasn't to do that, I could risk some parts of my widget flashing, which is really ugly in some cases.
So, although my first case could easily be addressed (using, for example, the approach you described), my second case is much more complex and not worth spending time on it since calling setUpdatesEnabled() to disable and then reenable updates works fine, just not when a QwtPlot object's legend... but I have now got it to work by 'manually' reenabling updates on my QwtPlot object's legend items.
Re: QwtLegend: different behaviour when inserting a legend after/before adding curves
Quote:
I need to customise a plot by modifying several of its properties (line, symbols, colours, etc.).
Well, update() only schedules a paint event ( in opposite to repaint what has an immediate effect ). So as long as you don't return to event loop you usually don't win anything by disabling updates.
Also the plot canvas usually has a backing store and as long as the size of the canvas is not changing and you don't invalidate the backing store ( by replot ) manually nothing expensive will happen.
Quote:
I need to customise a 'big' widget that can contain one or several plots (among other things). Because that widget is relatively 'heavy', I call setUpdatesEnabled() on it to disable updates, so that I can do my customisation. Once I am done with my customisation, I reenable updates on my 'big' widget.
Instead of calling the final update you could call replot on your plots. If you don't want to do this you could try to send QEvent::LayoutRequest to the plots instead. Those events will let the plots recalculate their layout - what should be the missing part to give your legend item a proper geometry. But as soon as you have a different layout, the size of the plot canvas changes and ...
Uwe