wirher
wirher

Reputation: 976

How to use mask with transparency on QWidget?

I am trying to use mask on my QWidget. I want to overlay existing widget with row of buttons - similar to Skype

skype buttons

Notice that these buttons don't have jagged edges - they are nicely antialiased and widget below them is still visible. I tried to accomplish that using Qt Stylesheets but on pixels that should be "masked out" was just black colour - it was round button on black, rectangular background.
Then I tried to do this using QWidget::mask(). I used following code

QImage alpha_mask(QSize(50, 50), QImage::Format_ARGB32);
alpha_mask.fill(Qt::transparent);

QPainter painter(&alpha_mask);
painter.setBrush(Qt::black);
painter.setRenderHint(QPainter::Antialiasing);    
painter.drawEllipse(QPoint(25,25), 24, 24);

QPixmap mask = QPixmap::fromImage(alpha_mask);
widget.setMask(mask.mask());

Sadly, it results in following effect
my buttons
"Edges" are jagged, where they should be smooth. I saved generated mask so I could investigate if it was the problem
enter image description here
it wasn't.

I know that Linux version of Skype does use Qt so it should be possible to reproduce. But how?

Upvotes: 5

Views: 4415

Answers (3)

user1095108
user1095108

Reputation: 14603

You are using the wrong approach for generating masks. I would generate them from the button images themselves:

QImage image(widget.size(), QImage::Format_Alpha8);
widget.render(&image);
widget.setMask(QBitmap::fromImage(image.createMaskFromColor(qRgba(0, 0, 0, 0))));

Upvotes: 0

Lupo Dharkael
Lupo Dharkael

Reputation: 53

I managed to get a nice circular button with not so much code. Here is the constructor of my custom button:

Button::Button(Type t, QWidget *parent) : QPushButton(parent) {
    setIcon(getIcon(t));
    resize(30,30);
    setMouseTracking(true);
    // here I apply a centered mask and 2 pixels bigger than the button
    setMask(QRegion(QRect(-1,-1,32,32),QRegion::Ellipse));
}

and in the style sheet I have the following:

Button {
    border-radius: 15px;
    background-color: rgb(136, 0, 170);
}

With border-radius I get the visual circle and the mask doesn't corrupt the edges because it is 1 pixel away.

Upvotes: 3

Emerald Weapon
Emerald Weapon

Reputation: 2540

One possible approach I see is the following.

  1. Prepare a nice high resolution pixmap with the circular button icon over transparent background.

  2. Paint the pixmap on a square widget.

  3. Then mask the widget leaving just a little bit of margin beyond the border of the circular icon so that the widget mask jaggedness won't touch the smooth border of the icon.

Upvotes: 3

Related Questions