Search code examples
c++qtqgraphicsviewqgraphicssceneqgraphicsitem

How to change the color of a QGraphicsRectItem


I want to change the color of a QGraphicsRectItem when a particular event occurs. The fact is that it seems that once the override paint method is called, the color won't change no matter what.

Simplified code of what I've done:

item.h:

class Item : public QGraphicsRectItem
{
public:
    Item(QGraphicsView *graphView);
    void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *) override;

private:
    QPointF newPos;
    QGraphicsView *graph;
};

item.cpp:

Item::Item(QGraphicsView *graphWidget) : graph(graphWidget) { }

void Item::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *)
{
     painter->setPen(Qt::NoPen);
     painter->setBrush(Qt::black);
     painter->drawEllipse(-7, -7, 20, 20);
}

main.cpp:

int main(int argc, char *argv[])
{
     srand(QDateTime::currentDateTime().toMSecsSinceEpoch());
     QApplication a(argc, argv);
     QGraphicsScene scene;
     QGraphicsView view(&scene);

     Item *item = new Item(&view);
     scene.addItem(item);
     item->setPos(0, 0);

     item->setBrush(Qt::red);
     item->update();

     view.show();
     return a.exec();
}

Solution

  • If I understand properly your question, the problem is that after item->setBrush(Qt::red), your circle is not being painter red. If this is the case, the problem is that you are forcing a specific pen (Qt::NoPen) and brush (Qt::red) in your paint function, and you are not using Item::pen() and Item::brush() to retrieve the information. Instead, you can do the following:

    Item::Item(QGraphicsView *graphWidget) : graph(graphWidget)
    {
      setPen(Qt::NoPen);
      setBrush(Qt::black);
    }
    
    void Item::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *)
    {
      Q_UNUSED(option);
      painter->setPen(pen());
      painter->setBrush(brush());
      painter->drawEllipse(-7, -7, 20, 20);
    }
    

    This way, you define the default pen and brush in the constructor, but you can still change them using Item::setPen and Item::setBrush. Moreover, for this example you would be better inheriting QAbstractGraphicsShapeItem but then you have to implement Item::boundingRectfunction. The following example outputs a red circle (which is what I suspect you want to do) and also draw the contour with black (although it is not what you wanted, but to show that pen also changes):

    #include <QApplication>
    #include <QDateTime>
    #include <QGraphicsRectItem>
    #include <QGraphicsScene>
    #include <QGraphicsView>
    
    class Item : public QAbstractGraphicsShapeItem
    {
    public:
      Item(QGraphicsView *graphView);
    
      void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *) override;
    
      virtual QRectF boundingRect() const override;
    
    private:
      QPointF newPos;
      QGraphicsView *graph;
    };
    
    Item::Item(QGraphicsView *graphWidget) : graph(graphWidget)
    {
      setPen(Qt::NoPen);
      setBrush(Qt::black);
    }
    
    void Item::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *)
    {
      Q_UNUSED(option);
      painter->setPen(pen());
      painter->setBrush(brush());
      painter->drawEllipse(-7, -7, 20, 20);
    }
    
    QRectF Item::boundingRect() const
    {
      double pw = pen().widthF() / 2;
      return QRectF(QPointF(-7 - pw, -7 - pw), QSizeF(20 + 2 * pw, 20 + 2 * pw));
    }
    
    int main(int argc, char *argv[])
    {
      srand(QDateTime::currentDateTime().toMSecsSinceEpoch());
      QApplication a(argc, argv);
      QGraphicsScene scene;
      QGraphicsView view(&scene);
    
      Item *item = new Item(&view);
      scene.addItem(item);
      item->setPos(0, 0);
    
      item->setBrush(Qt::red);
      item->setPen(QPen(Qt::black));
      item->update();
    
      view.show();
      return a.exec();
    }