PDA

View Full Version : QwtPlot inside a QGraphicsView



gibi70
19th January 2013, 18:01
I have placed several QwtPlots on a QGraphicsView used to resemble a textual document.
I want to use the zooming capabilities of the QGraphicsScene, of course.
This is what I get at default zooming factors, that is, a neat and perfect plot:

8598

But, when I operate some zooming on the scene, this is what I get:

8599

As you can see, the labels and the axes of the plot are still perfect and vectorial, whereas the canvas looks grainy, such as if it were a bitmap that has been scaled up.
What I do not understand is why the characters in the labels of the axes look good, but the canvas looks so horrible.
Any help or clue is appreciated, thanks.

Uwe
19th January 2013, 18:43
What happens when you disable the internal cache of the canvas ( see QwtPlotCanvas::setPaintAttribute() ) ?

Uwe

gibi70
19th January 2013, 21:42
Hi Uwe,


setPaintAttribute(QwtPlotCanvas::BackingStore, false)

did the trick, see below

8604

Thank you!

The print preview is still grainy (the axes, too), but after printing out it is quite unnoticeable

Uwe
20th January 2013, 09:35
I wouldn't disable the backingstore completely - instead invalidate it manually ( QwtPlotCanvas::invalidateBackingstore() ) when you zoom in/out.

But I strongly recommend not using QGraphicsView: you will run into problems like yours and serious performance issues when zooming in deep. You can zoom in/out using QwtPlot in a better way and QwtPlotRenderer is much more powerful for creating vector graphics.

As long as there is no real strong reason for embedding a QwtPlot widget into a QGraphicsView: don't do it !

Uwe

gibi70
20th January 2013, 15:12
Ok, I will disable and re-enable it during zooming operations.
Unfortunately, I need to place the plots inside a WYSIWYG document page that contains also text, images, and other things, for which I need to adopt a QGraphicsView.
I have a last question: how is it possible to reimplement the method QwtPlotCanvas::drawBorder? Do I need to reimplement also the whole QwtPlot and assemble manually the canvas (reimplemented), axes, and all other things?

Uwe
20th January 2013, 16:16
I have a last question: how is it possible to reimplement the method QwtPlotCanvas::drawBorder?

Better tell me what you want to do first.

Uwe

PS: if you want to use the zooming feature of QGraphicsView to see more details of the plot be warned, that this won't work, when the real device resolution is hidden behind logical geometries !

gibi70
20th January 2013, 16:36
I want to draw a one-pixel wide cosmetic black border all around the canvas, as in the previous pics I posted. I am currently doing it in the reimplementation of
QwtPlot::drawCanvas;, after finding that other existing methods did not work properly. I mean, it works perfectly now, I was just wondering whether reimplementing the QwtPlotCanvas::drawBorder method would have been cleaner and/or more elegant.

As for the zoom, there are two types I am using.

1 - fixed the zoom of the whole document page, the user can zoom in and out in the data series inside of the plot
2 - fixed the zoom in the plot, the user can zoom in and out in the document page

As far as I can tell and see, both methods are performing well and give very good results, also after your precious suggestion.

Uwe
20th January 2013, 19:56
I want to draw a one-pixel wide cosmetic black border all around the canvas, ...

canvas()->setLineWidth( 1 );
canvas()->setFrameStyle( QFrame::Plain | QFrame::Box );

HTH,
Uwe

gibi70
21st January 2013, 21:35
Hi Uwe, this is how I'd like the canvas (reimplementing drawCanvas)

8608

and this is how it appear setting the line width and style of the frame

8609

As you can see, there is a small extra space between the grid lines and the border.

Regarding the invalidation of the backingstore, as you wrote before, do I need to invalidate it before the zooming operation or just after having zoomed? Do I need to replot() in order to redraw the plot after that?

Uwe
22nd January 2013, 08:00
As you can see, there is a small extra space between the grid lines and the border.
See QwtPlotLayout::setCanvasMargin() or QwtPlotLayout::setAlignCanvasToScales().

Regarding the invalidation of the backingstore, as you wrote before, do I need to invalidate it before the zooming operation or just after having zoomed?
Thinking about it twice I guess ( have not checked it myself ) that QGraphicsView framework sets up a QPainter transformation for zooming, what will always end in something ugly, when there is a backing store. So disabling the backing store completely is probably the right solution.

The backing store of the canvas is important in combination with widget overlays ( f.e. rubber bands ), what will result in complete replots otherwise - often too slow for such operations. If you don't need them I wouldn't expect a problem with disabling it.

By the way: when I'm right with my guess above you should check if you want the following flag:


QwtPainter::setRoundingAlignment( false );Without aligning you might have effects because Qt aligns objects not properly ( f.e. the bottom/right borders of rects depending on left/top ), but with aligning I'm afraid Qwt aligns to logical coordinates and you will see rounding errors getting worse with increasing the zoom level.

One more comment: Qt renders before it clips, what might end in horrible performance issues, when you have lines very far outside the visible area. That's why Qwt does a polygon clipping ( QwtPlotCurve::ClipPolygons ) against the canvas geometries before passing the result to QPainter. In your layout you will have a huge canvas ( clipped by the viewport of the grahpics view ), what disables the effect of the polygon clipping. So be aware of this problem, when you want to zoom in very deep.

Uwe

gibi70
26th January 2013, 16:36
Hi Uwe, thanks for the hints.

Only a completely disabled backingstore works for the case above, any other combination of parameters did not produce good results. BTW, in this way canvas transparency is perfect, whereas in the other case there are strange graphical effects on it.

Unfortunately, I need to plot multiple permanent pickers on the canvas (uhm, I'd like to ask something on this too...), so I do see a slow down in that case. I am thinking about completely deleting and recreating the plot during the zooming operation, might it work?

gibi70
18th February 2013, 23:28
Hello Uwe, I hope you are still following this thread.
Everything works almost perfectly, after doing adjustments here and there.
However, I noticed a "problem" when exporting to PDF, which might not be entirely Qwt-related, I think.
If I export the single QwtPlot to PDF, it produces fine vectorial graphics on the PDF file itself. But, if I export to PDF the QGraphicsScene which contains the QwtPlot, it replaces the plot area (with labels, axes, and so on) with a bitmap.
Is that related to the fact that I put the QwtPlot itself inside a QGraphicsProxyWidget?

d_stranz
19th February 2013, 04:30
Is that related to the fact that I put the QwtPlot itself inside a QGraphicsProxyWidget?

I think that's correct - QGraphicsProxyWidget paints its content to a pixmap (which serves as a QPaintDevice). QwtPlot actually renders its content to a PDF printer in vector format to create the PDF output file.

You might be able to work around this by deriving a custom widget from QGraphiscProxyWidget and reimplementing whatever method is called to produce the PDF output. I am not sure how you merge the two bits of PDF though. The QwtPlot output is meant to be standalone, I think.

Uwe
19th February 2013, 08:34
The QwtPlot output is meant to be standalone, I think.
No - it isn't:


void QwtPlotRenderer::render( QwtPlot *, QPainter *, const QRectF & ) const;
Uwe

gibi70
22nd February 2013, 02:04
Ok, I have reimplemented QGraphicsProxyWidget in this way


class MyProxyWidget : public QGraphicsProxyWidget
{
public:

MyProxyWidget(QGraphicsItem * parent = 0, Qt::WindowFlags wFlags = 0)
: QGraphicsProxyWidget(parent, wFlags)
{
}

virtual void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget)
{
//QGraphicsProxyWidget::paint(painter, option, widget);
QwtPlotRenderer rdr;
rdr.render((QwtPlot *) this->widget(), painter, boundingRect());
}
private:
};

During common visualization on the GUI, the look is very good and with minor adjustments it could be even better. Now, when I export to pdf all the axes ticks, fonts, labels, etc, the grid lines, the plot title are vectorial, but they are huge! They almost fill all the space assigned to the plot item and practically no curve can be seen. Maybe it depends on the boundingRect() size I am passing to the render method?

Uwe
23rd February 2013, 13:02
No this should be because of the painter transformation - might be a problem of Qwt don't know.

I would try to do something like this:


virtual void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget)
{
if ( painter->paintEngine()->type() == QPaintEngine::Pdf )
{
painter->save();

const QRectF br = painter-> transform().mapRect( boundingRect() );
painter->resetTransform();

QwtPlotRenderer rdr;
rdr.render( (QwtPlot *) this->widget(), painter, br );

painter->restore();
return;
}

QGraphicsProxyWidget::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget);
}Uwe

gibi70
26th February 2013, 22:59
Yep, this works beautifully!