Skip to content
  • Categories
  • Recent
  • Tags
  • Popular
  • Users
  • Groups
  • Search
  • Get Qt Extensions
  • Unsolved
Collapse
Brand Logo
  1. Home
  2. Qt Development
  3. General and Desktop
  4. Custom QGraphicsItem-derived items keep repainting needlessly
QtWS25 Last Chance

Custom QGraphicsItem-derived items keep repainting needlessly

Scheduled Pinned Locked Moved General and Desktop
5 Posts 2 Posters 2.5k Views
  • Oldest to Newest
  • Newest to Oldest
  • Most Votes
Reply
  • Reply as topic
Log in to reply
This topic has been deleted. Only users with topic management privileges can see it.
  • N Offline
    N Offline
    neuviemep
    wrote on last edited by
    #1

    In my application, I have a QMdiArea which shows subwindows, which in turn contain QGraphicView-s visualising scenes with various custom items. Some of these are derived from QGraphicsPixmapItem and don't override paint() or boundingRect(), and some are totally custom and do override them. If I add any of these totally custom items to the scene, all items enter an endless paint() cycle on the event loop, making the CPU spike until the custom paint()-overriding item is removed from the scene. My code doesn't force the constant painting, and this happens as the application is idle, even when its main window has lost focus.

    Why does the event loop keep repainting all the items and how can I fix it?

    Qt version is the newest 5.0.2 binary bundle for Windows, and I am compiling the application using VS2012 for x64.

    1 Reply Last reply
    0
    • G Offline
      G Offline
      Guigui
      wrote on last edited by
      #2

      Any code you could share about those custom items?
      The loop may be caused by an update() call at the wrong place, like in the paint() method.

      1 Reply Last reply
      0
      • N Offline
        N Offline
        neuviemep
        wrote on last edited by
        #3

        Sorry, here's the code. I was hoping for generic tips on how to debug the event loop to find the source of the issue, to keep this brief...

        The items reside inside a QGraphicsView-derived GfxInteractiveView class which provides zoom-in/zoom-out functionality with the mouse wheel etc.

        The bottom item is GfxImageItem which is a thin layer on top of QGraphicsPixmapItem.

        On top of that there's a runtime generated pixmap item, also built on top of QGraphicsPixmapItem.

        And last there are the GfxPointItem-s on the very top, which are completely custom:

        @
        /// A draggable item representing an analysis point on the map, drawn on top of the map.
        class GfxPointItem : public QGraphicsObject
        {
        Q_OBJECT

        protected:
        GfxImageItem *imgParent_;
        GfxInteractiveImgView *view_;
        QRectF boundingRect_;
        bool active_, static_;
        QStaticText pointText_, valueText_;

        public:
        GfxPointItem(GfxImageItem *parent, GfxInteractiveImgView *view, const QPointF &pos);

        void setActive(bool arg);
        void setStatic(bool arg);
        void setColor(const QColor &color) { color_ = color; update(); }

        virtual QRectF boundingRect() const { return boundingRect_; }
        virtual void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget);

        signals:
        void changedPos(int index, QPointF newpos);

        public slots:
        void setPaintScale(qreal value);
        void setPointText(const QString &text);
        void setValueText(const QString &text);

        protected:
        void updateBoundRect();
        void updatePointText();
        QPoint valueTextPos() const;
        QPoint pointTextPos() const;
        };

        GfxPointItem::GfxPointItem(GfxImageItem *parent, GfxInteractiveImgView *view, const QPointF &pos, int index) : QGraphicsObject(parent),
        imgParent_(parent),
        view_(view),
        index_(index), size_(8), fontSize_(8),
        color_(Qt::black),
        paintScale_(view->invscale()),
        drawLabel_(true), active_(false), static_(false), floatPrec_(false)
        {
        QLOGX("Creating new at " << pos.x() << "," << pos.y() << ", index: " << index);
        setPos(pos);
        updatePointText();
        connect(view, SIGNAL(scaleChanged(qreal)), this, SLOT(setPaintScale(qreal)));
        }

        /// An inactive point wil not respond to hover events and will not be movable.
        void GfxPointItem::setActive(bool arg)
        {
        QLOGX("Setting active state: " << arg);
        active_ = arg;
        setAcceptHoverEvents(arg);
        setFlag(QGraphicsItem::ItemIsMovable, arg);
        }

        /// Set or disable static mode on point. In static mode, the point text is not updated when changing position, so it can retain a constant label.
        void GfxPointItem::setStatic(bool arg)
        {
        QLOGX("Setting static mode: " << arg);
        static_ = arg;
        }

        void GfxPointItem::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget)
        {
        QLOGX("Painting point");
        static const int margin = 2;
        setScale(paintScale_);
        QPen pen;
        pen.setWidth(1);
        pen.setColor(color_);
        painter->setPen(pen);

        // paint the centerpoint marker (two crossed lines)
        painter->drawLine(QPointF(-size_, 0), QPointF( size_, 0));
        painter->drawLine(QPointF(0, -size_), QPointF(0, size_));

        // the label box and the two static text lines inside
        pen.setWidth(0);
        painter->setPen(pen);

        QFont font;
        font.setPointSize(fontSize_);
        painter->setFont(font);

        QBrush brush(Qt::SolidPattern);
        brush.setColor(QColor(255, 255, 127)); // sand yellow
        painter->setBrush(brush);

        // point text size, value text size
        QSizeF pts = pointText_.size(),
        vts = valueText_.size();

        // point text position, value text position
        QPoint vtp = valueTextPos(),
        ptp = pointTextPos();

        // point id and position label and value indicator label in a rectangular box
        int shift = (valueText_.text().isEmpty()) ? 0 : vts.height();
        QRectF rect(ptp.x()-margin, ptp.y(), std::max(pts.width(), vts.width())+margin, pts.height() + shift);
        painter->drawRect(rect);
        painter->drawStaticText(ptp, pointText_);
        painter->drawStaticText(vtp, valueText_);
        }

        void GfxPointItem::setPaintScale(qreal value)
        {
        QLOGX("Updating scale: " << value);
        paintScale_ = value;
        update();
        }

        void GfxPointItem::setPointText(const QString &text)
        {
        QLOGX("Setting text: " << text);
        pointText_.setText(text);
        updateBoundRect();
        update();
        }

        void GfxPointItem::setValueText(const QString &text)
        {
        QLOGX("Setting value text: " << text);
        valueText_.setText(text);
        updateBoundRect();
        update();
        }

        void GfxPointItem::updateBoundRect()
        {
        QLOGX("Updating bounding rect");
        boundingRect_.setRect(- size_, pointTextPos().y(),
        (2 * size_) + std::max(pointText_.size().width(), valueText_.size().width()),
        (2 * size_) + pointText_.size().height() + valueText_.size().height());
        }

        void GfxPointItem::updatePointText()
        {
        QLOGX("Updating point text");
        pointText_.setText("P" + QString::number(index_ + 1) + " ("

        • (floatPrec_ ? QString::number(pos().x()) : QString::number(std::floor(pos().x()))) + ","
        • (floatPrec_ ? QString::number(pos().y()) : QString::number(std::floor(pos().y()))) + ")");

        updateBoundRect();
        update();
        }

        void GfxPointItem::mouseMoveEvent(QGraphicsSceneMouseEvent *event)
        {
        QLOGX("Mouse move");
        QPointF p = pos();
        QPointF ep = event->pos();

        QGraphicsItem::mouseMoveEvent(event);

        if (!static_) updatePointText();
        emit changedPos(index_, pos());
        }
        @

        When I add a GfxPointItem to the scene, the log shows:

        GfxImageItem::paint(): Painting image
        GfxMapItem::paint(): Painting map
        GfxPointItem::paint(): Painting point
        GfxImageItem::paint(): Painting image
        GfxMapItem::paint(): Painting map
        GfxPointItem::paint(): Painting point
        [...]

        in infinite succession, and the log file grows for as long as the point item is present in the scene. To my knowledge, there's nothing that should cause this.

        Thanks!

        1 Reply Last reply
        0
        • N Offline
          N Offline
          neuviemep
          wrote on last edited by
          #4

          By placing tracing statements in various overrides of event functions, I've been able to establish that the event that forces the items to repaint comes from the view, not from any of the items. Also, the window that contains the view doesn't seem to be the culprit (its paintEvents were few).

          Still no idea what makes the view believe it needs to constantly repaint all its items after GfxPointItem is added.

          1 Reply Last reply
          0
          • N Offline
            N Offline
            neuviemep
            wrote on last edited by
            #5

            Turned out the problem was the call to setScale in the item's paint(), which invalidated the area and forced the view to repaint it (with all 3 items) - which caused it to get invalidated again. That in case someone was wondering.

            1 Reply Last reply
            0

            • Login

            • Login or register to search.
            • First post
              Last post
            0
            • Categories
            • Recent
            • Tags
            • Popular
            • Users
            • Groups
            • Search
            • Get Qt Extensions
            • Unsolved