PDA

View Full Version : drawForeground update trouble



spud
23rd January 2008, 18:06
I'm having problems using the QGraphicsView to implement overlays. I simply would like to draw a semi-transparent box with fixed widget coordinates, containing some text. I thought drawForeground() would be the perfect solution. I get the widget coordinates from the viewport(ignoring the scrollbars) turn of the world matrix and paint.

The result looks good at first, but then something goes wrong. The viewport seems to cache the contents and doesn't always ask for an update when I scroll.
I've attached to screenshots and a full example. Does anybody have an idea how I can provoke an update, or if I am doing something wrong? I'm using Qt 4.3.2 on a windows machine

#include <QtGui>

QString text = "Lorem ipsum dolor sit amet, consectetur adipisicing elit, "
"sed do eiusmod tempor incididunt ut labore et dolore magna "
"aliqua. Ut enim ad minim veniam, quis nostrud exercitation "
"ullamco laboris nisi ut aliquip ex ea commodo consequat. "
"Duis aute irure dolor in reprehenderit in voluptate velit ...";

class GraphicsView : public QGraphicsView
{
public:
GraphicsView(QGraphicsScene* scene)
: QGraphicsView(scene)
{
}
QRectF overlayRect()const
{
return QRectF(viewport()->rect().width()-220, 20, 200, 200);
}
void drawForeground(QPainter *painter, const QRectF &rect)
{
painter->save();
painter->setWorldMatrixEnabled(false);
painter->setPen(QPen(Qt::darkGray, 2));
painter->setRenderHint(QPainter::Antialiasing);
painter->setBrush(QColor(0,0,0,10));
painter->drawRoundRect(overlayRect());
painter->drawText(overlayRect().adjusted(20, 20, -20, -20), Qt::TextWordWrap , text);

painter->setWorldMatrixEnabled(true);
painter->restore();
QGraphicsView::drawForeground(painter, rect);
}
void scrollContentsBy(int dx, int dy)
{
// can I force an update here
QGraphicsView::scrollContentsBy( dx, dy);
}
};

int main(int argc, char* argv[])
{
QApplication app(argc, argv);
QGraphicsScene scene;
scene.setSceneRect(0,0,2000,2000);
GraphicsView view(&scene);
view.show();
return app.exec();
}

P.S. The problem goes away if I pass the flag QGraphicsView::FullViewportUpdate, or use an OpenGL viewport, but I need a software rendering mode and would rather keep the updates to a minimum.

Bitto
23rd January 2008, 20:09
Seems what you're wanting is a viewport aligned overlay item. Graphics View doesn't support this, and drawForeground() is the wrong function to reimplement - it's there to render the front layer of the scene, in scene coordinates. Disabling the matrix is a hack that rarely gets you where you want.

Usually people implement overlays for QGraphicsView by reimplementing paintEvent(), calling the base implementation and simply rendering on top of the viewport contents with QPainter. To avoid the problems with scrolling, you can either reimplement the scrollContentsBy() function and update the viewport with the overlay region, or set the viewportUpdateMode() to FullViewportUpdate. Using an OpenGL viewport also solves the scrolling problem without any extra action needed.

wysota
23rd January 2008, 22:35
Maybe moving the overlay item in the scene as the viewport gets scrolled might be an option as well? I know it's stupid and you shouldn't do that, but it might just work. Of course it'll break once you start zooming...

spud
24th January 2008, 00:03
Thanks guys, I guess I was so thrilled about GraphicsView I tried to use it as a Golden Hammer (http://en.wikipedia.org/wiki/Golden_hammer). Perhaps this functionality should be provided by the graphics view/scene framework, though. All I need is a function to invalidate a certain area in the viewport. I always thought the scene was all about scene coordinates and the view all about the screen display. I'm of good hope, since last time (http://www.qtcentre.org/forum/f-qt-programming-2/t-implementing-scale-invariant-qgraphicsitems-4167.html) I found a feature lacking within the framework you came up with QGraphicsItem::ItemIgnoresTransformations in no time.

wysota
24th January 2008, 00:21
All I need is a function to invalidate a certain area in the viewport.

There is QGraphicsScene::invalidate and QWidget::update(QRect).

acestrong
29th June 2009, 03:22
Thanks for your code!

Actually you can add
this->viewport()->update(); to solve your problem.

crayzeewulf
28th March 2011, 00:46
Thanks acestrong. I had the same problem and the viewport update trick you suggested worked like a charm. :)