Incorrect exposedRect in QGraphicsWidget::paint()
-
Hi,
In my application I have multiple, rather big custom GraphicsWidgets (derived from QGraphicsWidget). To speed up drawing I fall back on QStyleOptionGraphicsItem::exposedRect in my QGraphicsWidget::paint() reimplementations. If the GraphicsWidgets are managed by a QGraphicsLayout or positioned manually via setGeometry() the exposedRect provides wrong size information under certain conditions. Here is a minimal example that should illustrate the problem:
The QGraphicsView shows three Bar objects. In the paint() function of the Bar objects only the exposedRect is drawn (for every paint() invocation the colour is toggled).
Every Bar obj. grows in its height by one pixel if the appropriate button is clicked.
If the topmost button is clicked everything works as expected (boundingRect equals exposedRect in every paint() call):
If the second button is clicked the exposedRect of the first Bar realigns to QRectF(0,49 382x2) although the first Bar should be fully visible (geometry: QRectF(9,9 382x51)). The third button triggers the same glitch for the second Bar.
I don't understand why exposedRect shows this behaviour. Can someone clarify?
I've tested with:
Qt5.4.1 MSVC2013 OpenGL 32Bit
Qt5.3.2 MSVC2013 OpenGL 32Bit
Best Regardsminimal.h
#include <QGraphicsItem> #include <QGraphicsWidget> #include <QGraphicsScene> #include <QGraphicsLinearLayout> #include <QStyleOptionGraphicsItem> #include <QGridLayout> #include <QPushButton> #include <QWidget> class Bar : public QGraphicsWidget { Q_OBJECT public: Bar(QPushButton *pButton, QGraphicsItem *pParent = 0) : QGraphicsWidget(pParent), mToggleColor(false) { setFlag(QGraphicsItem::ItemUsesExtendedStyleOption); setMinimumSize(100., 20.); connect(pButton, SIGNAL(clicked()), this, SLOT(Grow())); } virtual ~Bar() {} void paint(QPainter *pPainter, const QStyleOptionGraphicsItem *pOption, QWidget *pWidget = 0) { const QRectF exposed_rect = pOption->exposedRect; QPen pen; pen.setColor(Qt::magenta); pen.setWidth(1); pPainter->save(); pPainter->setPen(pen); if(mToggleColor)pPainter->fillRect(exposed_rect, Qt::green); else pPainter->fillRect(exposed_rect, Qt::yellow); QRectF border_rect = exposed_rect; border_rect.setHeight(border_rect.height() - 1); border_rect.setWidth(border_rect.width() - 1); pPainter->drawRect(exposed_rect); mToggleColor = !mToggleColor; pPainter->restore(); } public slots: void Grow() { int old_height = boundingRect().height(); setMinimumHeight(old_height + 1); } private: bool mToggleColor; };
main.cpp
#include "minimal.h" #include <QApplication> #include <QGraphicsView> #include <QGraphicsItem> #include <QGraphicsWidget> #include <QGraphicsScene> #include <QGraphicsLinearLayout> #include <QStyleOptionGraphicsItem> #include <QGridLayout> #include <QPushButton> #include <QWidget> int main(int argc, char *argv[]) { QApplication app(argc, argv); QWidget widget; QGraphicsScene scene; QGraphicsWidget *p_graphics_widget = new QGraphicsWidget(0, Qt::Window); p_graphics_widget->setGeometry(20, 50, 400, 500); QPushButton *p_button_one = new QPushButton("Grow one", &widget); QPushButton *p_button_two = new QPushButton("Grow two", &widget); QPushButton *p_button_three = new QPushButton("Grow three", &widget); Bar *p_bar_one = new Bar(p_button_one, p_graphics_widget); Bar *p_bar_two = new Bar(p_button_two, p_graphics_widget); Bar *p_bar_three = new Bar(p_button_three, p_graphics_widget); QGraphicsLinearLayout *p_graphics_layout = new QGraphicsLinearLayout(Qt::Vertical); p_graphics_layout->setSpacing(0.); p_graphics_layout->addItem(p_bar_one); p_graphics_layout->addItem(p_bar_two); p_graphics_layout->addItem(p_bar_three); p_graphics_layout->addStretch(99); p_graphics_widget->setLayout(p_graphics_layout); scene.addItem(p_graphics_widget); scene.setBackgroundBrush(Qt::white); scene.setSceneRect(scene.itemsBoundingRect()); QGraphicsView view(&scene); QGridLayout *p_layout = new QGridLayout(); p_layout->addWidget(&view, 0, 0); p_layout->addWidget(p_button_one, 1, 0); p_layout->addWidget(p_button_two, 2, 0); p_layout->addWidget(p_button_three, 3, 0); widget.setLayout(p_layout); widget.show(); view.show(); return app.exec(); }
-
Keep Your drawing inside boundingRect() or in Your case exposed area. Probably in this case this will be the same for parent widget interaction i.e. mowing widget but will change when painting separate elements inside .
Anyway issue is with Your drawing of border.
QRectF border_rect = exposed_rect; border_rect.adjust( pen.widthF(), pen.widthF(), -pen.widthF(), -pen.widthF()); pPainter->drawRect(border_rect);
Zoom in image to see that each rectangle is inside boundingbox().