YamHon.CHAN
YamHon.CHAN

Reputation: 886

painting QLinearGradient in QGraphicsScene

I originally implement my graph by drawing all the content in the QWidget::paintEvent(). I have a function drawHeatMapLegend() to draw a box with QLinearGradient to represent a heat-map for my graph as legend.

Original implementation

widMapGraph::widMapGraph(QWidget parent = 0) : QWidget(parent) {
    gradient_.setCoordinateMode(QGradient::ObjectBoundingMode);
    gradient_.setColorAt(0.0, Qt::green);
    gradient_.setColorAt(0.3, Qt::yellow);
    gradient_.setColorAt(0.6, Qt::red);
}

void widMapGraph::paintEvent(QPaintEvent *event) {
    QPainter painter(this);
    drawHeatMapLegend(&painter);
}

void widMapGraph::drawHeatMapLegend(QPainter* painter) {
    QRect legendBox(30, 70, 25, 100);
    int left = legendBox.left() + legendBox.width() + 10;
    painter->save();
    painter->setPen(QPen());
    painter->setBrush(gradient_);
    painter->drawRect(legendBox);
    painter->drawText(left, legendBox.top(), "0.00%");
    painter->drawText(left, legendBox.top() + legendBox.height() / 2, "50.00%");
    painter->drawText(left, legendBox.top() + legendBox.height(), "100.00%");
    painter->restore();
} // end: (widMapGraph::drawHeatMapLegend)

Now, I try to use QGraphicScene/QGraphicsView framework for my graph and I implement a subclass of QGraphicsRectItem for my map legend.

Class definition

class MapLegend : public QObject, public QGraphicsRectItem {
    Q_OBJECT
public:
    MapLegend(QGraphicsItem *parent = 0);
    void paint (QPainter *painter,
                const QStyleOptionGraphicsItem *option,
                QWidget *widget);
    QLinearGradient gradient_;
    /* other members */
}

Class implementation

MapLegend::MapLegend(QGraphicsItem *parent) : QGraphicsRectItem(parent) {
    setRect(30, 70, 25, 100);
    gradient_.setCoordinateMode(QGradient::ObjectBoundingMode);
    gradient_.setColorAt(0.0, Qt::green);
    gradient_.setColorAt(0.3, Qt::yellow);
    gradient_.setColorAt(0.6, Qt::red);
} // end_ctor(MapLegend)

void MapLegend::paint(QPainter *painter,
                      const QStyleOptionGraphicsItem *option,
                      QWidget *widget)
{
    Q_UNUSED(option);
    Q_UNUSED(widget);
    int left = rect().left() + rect().width() + 10;
    painter->setPen(QPen());
    painter->setBrush(gradient_);
    painter->drawRect(rect());
    painter->drawText(left, rect().top(), "0.00%");
    painter->drawText(left, rect().top() + rect().height() / 2, "50.00%");
    painter->drawText(left, rect().top() + rect().height(), "100.00%");
} // end: MapLegend::paint()

void My2ndGraph::task() {
    myView->scene()->clear();
    myView->scene()->addItem(myLegend); // myLegend is a class variable as MapLegend
    update();
}

Result The orange box shows two examples using 2nd implementation

Result

Question The original implementation correctly show a gradient 'vertically' along the box, but the new implementation draw the gradient diagonally. Is there anything I missed that why the two implementations behavior dis-agree? Thanks

Upvotes: 2

Views: 3441

Answers (1)

cmannett85
cmannett85

Reputation: 22346

You haven't set the start and stop end points of the gradient, so it defaults to using the top left and bottom right corners:

QLinearGradient::QLinearGradient() Constructs a default linear gradient with interpolation area between (0, 0) and (1, 1).

and:

QGradient::ObjectBoundingMode: In this mode the gradient coordinates are relative to the bounding rectangle of the object being drawn, with (0,0) in the top left corner, and (1,1) in the bottom right corner of the object's bounding rectangle.

So you will need to manually tell it the gradient direction, like this:

gradient_.setStart( 0.0, 0.0 );
gradient_.setFinalStop( 0.0, 1.0 );

Or when initialised:

MapLegend::MapLegend(QGraphicsItem *parent) : QGraphicsRectItem(parent),
    gradient_( QLinearGradient( 0.0, 0.0, 0.0, 1.0 ) ) { ... }

As for why it worked inside a QWidget? I have no idea, it shouldn't have!

Upvotes: 2

Related Questions