Search code examples
qt5qpainter

Can I use a QPainter to draw a line with a per-vertex color?


I have a custom Qt 5 widget that renders itself using QPainter. I would like to be able to draw a line where each vertex is associated with a different color, and the color is interpolated accordingly along the lines joining the points. Is this possible?


Solution

  • I think you'll need to perform the drawing on a line-by-line basis. Assuming that's acceptable then a QPen initialized with a suitable QLinearGradient should work...

    class widget: public QWidget {
      using super = QWidget;
    public:
      explicit widget (QWidget *parent = nullptr)
        : super(parent)
        {
        }
    protected:
      virtual void paintEvent (QPaintEvent *event) override
        {
          super::paintEvent(event);
          QPainter painter(this);
    
          /*
           * Define the corners of a rectangle lying 10 pixels inside
           * the current bounding rect.
           */
          int left = 10, right = width() - 10;
          int top = 10, bottom = height() - 10;
          QPoint top_left(left, top);
          QPoint top_right(right, top);
          QPoint bottom_right(right, bottom);
          QPoint bottom_left(left, bottom);
    
          /*
           * Insert the points along with their required colours into
           * a suitable container.
           */
          QVector<QPair<QPoint, QColor>> points;
          points << qMakePair(top_left, Qt::red);
          points << qMakePair(top_right, Qt::green);
          points << qMakePair(bottom_right, Qt::blue);
          points << qMakePair(bottom_left, Qt::black);
          for (int i = 0; i < points.size(); ++i) {
            int e = (i + 1) % points.size();
    
            /*
             * Create a suitable linear gradient based on the colours
             * required for vertices indexed by i and e.
             */
            QLinearGradient gradient;
            gradient.setColorAt(0, points[i].second);
            gradient.setColorAt(1, points[e].second);
            gradient.setStart(points[i].first);
            gradient.setFinalStop(points[e].first);
    
            /*
             * Set the pen and draw the line.
             */
            painter.setPen(QPen(QBrush(gradient), 10.0f));
            painter.drawLine(points[i].first, points[e].first);
          }
        }
    };
    

    The above results in something like...

    enter image description here

    (Note: There may be a better way to achieve this using QPainterPath and QPainterPathStroker but I'm not sure based on the docs. I've looked at.)