Frank
Frank

Reputation: 2696

QPainter composition not working as expected with background

I'm trying to draw two rectangles with same color and transparency on a QFrame with a white background. These rectangles should overlap and the their transparency should not change (also in the overlapping region). So like this:

enter image description here

Here is the code I have so far:

class Canvas : public QFrame
{
public:
    void paintEvent(QPaintEvent * event) override;
};

void Canvas::paintEvent(QPaintEvent *event)
{
    QPainter painter( this );

    painter.setPen(QPen(Qt::NoPen));
    painter.setBrush(QBrush(QColor(0,0,255,125)));

    painter.drawRect(QRect(10,10,100,100));
    painter.setCompositionMode(QPainter::CompositionMode_Source);
    painter.setBrush(QBrush(QColor(0, 0, 255, 125)));
    painter.drawRect(QRect(80, 80, 100, 100));
}

int main( int argc, char **argv )
{
    QApplication a( argc, argv );

    Canvas canvas;
    canvas.setAutoFillBackground(true);
    QPalette pal;
    pal.setColor(QPalette::Window, QColor(Qt::red));
    canvas.setBackgroundRole(QPalette::Window);
    canvas.setPalette(pal);
    canvas.show();

    return a.exec();
}

However this produces the following image:

enter image description here

I have tried every possible composition mode for the painter, but none seem to give me the desired effect. I guess CompositionMode_Source is the correct one since if I use the following code:

QPixmap pixmap(200, 200);
pixmap.fill(Qt::transparent);

QPainter painter(&pixmap);
painter.setPen(QPen(Qt::NoPen));
painter.setBrush(QBrush(QColor(0, 0, 255, 125)));

painter.drawRect(QRect(10, 10, 100, 100));
painter.setCompositionMode(QPainter::CompositionMode_Source);
painter.setBrush(QBrush(QColor(0, 0, 255, 125)));
painter.drawRect(QRect(80, 80, 100, 100));

QLabel label;
label.setPixmap(pixmap);
label.show();

I do get the desired effect (but without the red background):

enter image description here

However if I change the fill to Qt::red I get again:

enter image description here

What am I missing here? How can I get my desired effect? The actual application for this is that I want to draw rectangles on a QFrame derived class which is implemented in a third party lib over which I have limited control.

Upvotes: 2

Views: 1783

Answers (1)

peppe
peppe

Reputation: 22744

I spot three problems with the code:

  1. the first rectangle is drawn with alpha blending (Source Over mode) because you're setting the composition mode after the first draw call. The second one instead uses Source mode (i.e. copy the source pixels as-is, do not perform alpha blending).
  2. Indeed Source does not perform alpha blending, which you seem to want. So don't use that! The default composition mode does what you want.
  3. Drawing two different shapes will perform composition between them. That's obviously expected, since you're doing two draw calls; the second draw call will find the destination already changed by the first. If you don't want that, you must find a way to draw both shapes in one draw call (for instance: add both of them to one QPainterPath, then draw the path in one draw call), or perform composition at a later stage (for instance: draw them onto an opaque QImage, then blend the image over the destination in one draw call).

Upvotes: 4

Related Questions