QGraphicsItem paint event called continually during QWidget::event loop



  • I am creating an application with a QMainWindow, QGraphicsScene and QGraphicsView with many QGraphicsItems within the view. My items' paint() method is being called continually and I only want them to be called when I update an item. I backtraced the item's paint call and here is what is happening:

    The main window's QWidget::event calls QWidgetPrivate::drawWidget which calls QWidgetPrivate::sendPaintEvent and that calls QGraphicsView paintEvent. This draws the items in the scene and calls paint on each item. The loop repeats continually. How do I stop this/why is this happening in the first place? I was under the impression that an item's paint event is called during update() or repaint(). I never call these functions.


  • Lifetime Qt Champion

    Hi and welcome to devnet,

    The paint event should happen when needed (e.g moving a window) or requested (e.g. with update).

    However, without seeing your code, it's pretty much impossible to get an idea about what might be going wrong.



  • Hi,

    Fair enough. I can't post my exact code for privacy reasons but this is an abstracted version:
    mainwindow.h

    class MainWindow : public QMainWindow
    {
        Q_OBJECT
    
    private:
       Frame* myFrame;
    };
    

    mainwindow.cpp

    MainWindow::
    MainWindow( QWidget *parent ) :
    QMainWindow(parent)
    {
    setCentralWidget(myFrame);
    }
    
    bool MainWindow::
    event( QEvent *event ) {
        if ( event->type( ) == QEvent::WindowStateChange ) {
            if ( this->windowState( ).testFlag( Qt::WindowMinimized ) ) {
                // Tell other windows
                emit notifyControl_minimizeApplicationWindow( );
                LOG(INFO) << "hiding";
                return true;
            } else if ( this->windowState( ).testFlag( Qt::WindowNoState ) ) {
                emit notifyControl_restoreApplicationWindow( );
                    LOG(INFO) << "restoring";
                return true;
            }
        }
       return QWidget::event( event );
    }
    

    frame.h

    class Frame :public QFrame 
    {
       Q_OBJECT
    
    private:
    QGraphicsView* myGraphicsView; 
    DiagramScene* myScene; 
    };
    

    frame.cpp

    Frame::
    Frame(MainWindow* parent)
    {
        myDiagramScene = new DiagramScene(  this );
        myGraphicsView = new QGraphicsView( this );
        myGraphicsView->setScene( myScene );
    }
    

    diagramscene.h

    class DiagramScene : public QGraphicsScene
    {
    Q_OBJECT
    
    private:
    QVector<Rectangle*> myItems;
    };
    

    diagramscene.cpp

    DiagramScene::
    DiagramScene(Frame* parent) : 
    QGraphicsScene(parent)
    {
    //create and add items to the scene here
    }
    

    rectangle.h

    class Rectangle : public QGraphicsRectItem
    {
    public:
        int type( ) const Q_DECL_OVERRIDE { return Type; }
        void updatePosition( );
    
        void paint( QPainter *painter, const QStyleOptionGraphicsItem *, QWidget *widget = 0 ) Q_DECL_OVERRIDE;
        void contextMenuEvent(QGraphicsSceneContextMenuEvent *event);
    private:
    QGraphicsLineItem* myLine;
    };
    

    rectangle.cpp

    Rectangle::Rectangle()
    QGraphicsRectItem()
    {
    setLine();
    setRectangle();
    }
    
    void Rectangle::
    paint( QPainter *painter, const QStyleOptionGraphicsItem *, QWidget * )
    {
        painter->setPen( this->myColor );
        painter->setRenderHints(QPainter::Antialiasing |  QPainter::HighQualityAntialiasing);
        if ( this->isSelected( ) )
        {
            painter->setPen( QPen( Qt::red, 2 ) );
            painter->setBrush( QColor( Qt::red ) );
        }
        else
        {
            painter->setPen( QPen( Qt::blue, 2) );
            painter->setBrush( QColor( Qt::blue ) );
        }
        painter->drawRect( this->rect( ) );
        painter->drawLine( this->myLine->line( ) );
    }
    

    Hope this helps

    Edit - added code tags - p3c0


  • Moderators

    @qtshah While posting the code enclose them within ```


  • Lifetime Qt Champion

    Is it normal that you don't use any layout in your Frame class ?



  • My mistake there is a layout in the Frame class.

    QHBoxLayout * layout = new QHBoxLayout;
    layout->addWidget(myGraphicsView);
    setLayout(layout);
    

  • Lifetime Qt Champion

    So now it's working as you want ?



  • No the paint method is still being called repeatedly for each rectangle in the scene, which is time consuming. I only want paint to be called when something changes in the rectangle like when it is moved or the color is changed. It may be that I am misunderstanding when the paint method is triggered. Is it supposed to be triggered at every QWidget event? Because that is what seems to be happening right now.


  • Lifetime Qt Champion

    One other detail, you are not calling the correct base class implementation of MainWindow.

    Also, do you really need Frame ? Looks like you could put the QGraphicsView directly as central widget, no ?



  • No the QFrame is not necessary, we will need to refactor that. I'm not sure what you mean by not calling the correct base class implementation. Are you referring to the QMainWindow constructor?


  • Lifetime Qt Champion

    In MainWindow::event, you are not calling QMainWindow::event but QWidget::event.



  • Oh yes that is true. I tried switching it to QMainWindow::event but the result was the same


  • Lifetime Qt Champion

    What else are you doing in your application ?



  • We have a palette of icons in a dock widget that the user can add into the scene, copy, paste and delete. Each graphics item has a proxy widget that holds properties for the item. The items are rectangles and lines that connect between them so that moving a rectangle should move the lines that are connected to it. I want the items to update at a reasonable event, for example a mouse release event, instead of repeatedly like they doing now which is causing some lag. Basically I want to install an event filter, but am first trying to understand why all QMainWindow events are triggering a graphics item paint.


  • Lifetime Qt Champion

    By proxy do you mean you have QProxyGraphicsProxyWidget ?



  • yes that's it


  • Lifetime Qt Champion

    How many are they at once on your scene ?



  • There's no limit to how many can be in the scene and the scenes are likely to get complicated . Most likely there will be between ~10 and ~50 items at a time.


  • Lifetime Qt Champion

    Are you still experiencing that if you avoid the proxy widgets ?



  • Yes we are



  • This post is deleted!

  • Lifetime Qt Champion

    Is the code accessible somewhere to be tested ?



  • Hi sorry for the late response. We figured out the problem. Within the paint function of the rectangle we were updating the line and this was causing an infinite paint loop. Thank you for your help!


  • Lifetime Qt Champion

    Glad you found out and thanks for sharing !

    Since you have it working now, please mark the thread as solved using the "Topic Tools" button so that other forum users may know a solution has been found :)


Log in to reply
 

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