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):
    alt text

    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?
    alt text
    I've tested with:
    Qt5.4.1 MSVC2013 OpenGL 32Bit
    Qt5.3.2 MSVC2013 OpenGL 32Bit
    Best Regards

    minimal.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.
    alt text

            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().


Log in to reply
 

Looks like your connection to Qt Forum was lost, please wait while we try to reconnect.