Using an alpha transparent mask on a QWidget? - qt

Is it possible to assign an alpha-transparent mask to a QWidget? I know how to set a mask using setMask but it seems it only supports black&white masks. Is it possible to make it support a true alpha channel?
i.e. currently I have a PNG like this:
and a widget like this:
If I load my PNG in a QPixmap and set it as a mask, I get this (notice the edges):
However I would like to get this (smooth edges):
Any idea how to do that?
Note: I'm doing some more complex drawing on the widget, which must be restricted to the mask area, so I cannot simply set my PNG as the widget's background image.

I think your best route is in QPainter's composition modes.
For example:
QPixmap PixmapToBeMasked(Size);
PixmapToBeMasked.fill(QColor(255, 255, 255, 120));
QPixmap Mask = DoSomethingToGetAMask();
QPainter Painter(&PixmapToBeMasked);
Painter.setCompositionMode(QPainter::CompositionMode_DestinationIn);
Painter.drawPixmap(0, 0, Mask.width(), Mask.height(), Mask);
That will handle drawing your widget nicely. If you still need to mask mouse events you might need to do some extra work though.

Related

Transparent QGraphicsWebview over QGLWidget leads to super imposed images

I have a transparent QGraphicsWebview inside a QGraphicsView with the following settings:
The QGraphicsView is the high level widget, and is shown in full screen mode
The graphics view uses a QGLWidget as its view port (to use opengl-es)
Alpha channel and double buffering are enabled in this QGLWidget
Transparency is achieved by graphicsView->setStyleSheet("background:transparent")
Following attributes are set for QGraphicsView and QGraphicsWebview
WA_TranslucentBackground = true
WA_NoSystemBackground = true
WA_OpaquePaintEvent = false
The QPalette::Base and QPalette::Window brushes of webview and webview->page() are set to Qt::transparent
At the beginning, the transparency works fine. But as the screen get updated (when I scroll), it looks like the new bitmap is blended on top of the existing one to get a superimposed picture. After about 5-6 screen updates, this blending causes the colors to accumulate and form an opaque rectangle (with a corrupted image). Following images show first, second and final stages of the problem.
How do I tell qt/opengl to stop blending and just draw the new image to the frame buffer?
I tried calling fillRect(boundRect(), Qt::transparent) from overridden Webview::paint and GraphicsView::paintEvent; but it didn't work except for making the updates slower.
I am new to Qt and OpenGl, so I might be missing some basic flags or settings.
I tried all the methods mentioned above. They did not work for me. I then debugged into qtbase code and found that setting the Opacity level make the top browser layer transparent.
this->setOpacity(0.1);
this pointer points to the QGraphicsWebView object.
With this method, the whole front browser contents including background will be transparent. To separate header, paragraph and background and to specify different transparent levels for them, I will have to dig into webkit code a little further to figure out the problem. But for now, setOpacity() did the trick and is good enough for what I am doing.
It turns out the problem is graphicsView->setStyleSheet("background:transparent");. Who would have guessed?!
Yeah, the line that I thought made transparency work was actually causing troubles with transparency. The application works fine without that line (or if you change it to background:none)
In short, steps to get a transparent QGraphicsWebview using QGLWidget:
Set the Base palettes of QGraphicsWebview, QWebpage and the outer QGraphicsView to Qt::transparent
scene->setBackgroundBrush(QBrush(Qt::transparent));
You should also make sure that html body background is set to transparent values:
html, body {
background-color: rgba(127, 127, 0, 0.5);
}

Change color of transparent image in Qt

I have a transparent image (QImage) overlayed over a video in Qt. I want to change the color of the transparent image only on clicks of button. Can some one tell me how to do this?
Thank You.
This can be done in many ways. I suggest to use QPainter to create new image. If you set SourceIn composition mode, starting image's alpha channel will be applied to any drawing that you will do. You just need to fill image with desired color.
QPixmap source_image; // should be preserved in a class member variable
QRgb base_color; // desired image color
QPixmap new_image = source_image;
QPainter painter(&new_image);
painter.setCompositionMode(QPainter::CompositionMode_SourceIn);
painter.fillRect(new_image.rect(), base_color);
painter.end();
ui->label->setPixmap(new_image); // showing result
Note that I use QPixmap instead of QImage because QPixmaps are more efficient to display (and possibly paint). If you for some reason still want to use QImage, this code will work with QImage without any changes (excluding the last line of course).
Source image:
Result:

QT : Masking an image - Suggestions?

I dont know if I am using the correct term here. However this is what I am trying to achieve and I would like some suggestions on how I could achieve that. I want to have a circle with border visible. Now here is the hard part and something I dont even know how to start with. I want to manipulate the circle in such a way that the borders of the circle are visible and its center is not (i.e Pretty much that it has a hole in it and would show what ever is placed under it)I would then like to have another image placed under the circle such that only the part of the image that is under the transparent part of the circle is shown the parts outside the transparent boundary of the circle become invisible. Any suggestions on how I could achieve this. It seems that googling isnt helping me.
I would suggest the alternative way for unmasking a circular area of an image. You can specify the clip region - the area where you need to perform painting. For example:
[..]
QPainter painter(this);
// Sample circular area.
QRegion r(QRect(100, 100, 200, 200), QRegion::Ellipse);
painter.setClipRegion(r);
[..]
painter.drawImage(0, 0, image);
[..]
This will draw only those parts of your image that are inside of the circle with radius 200. All the rest pixels will be hidden.
You can handle mouse move event to move this "circle" over the image like a loupe.
UPDATE
Below is the sample code that generates an image with circular mask and insert it into the label:
QPixmap target(500, 500); // the size may vary
QPixmap source("image.png");
QPainter painter(&target);
QRegion r(QRect(100, 100, 200, 200), QRegion::Ellipse);
painter.setClipRegion(r);
painter.drawPixmap(0, 0, source);
QLabel l;
l.setPixmap(target);
l.show();
You might want to have a look at the Composition Example.
In short you could draw the first image and then use one of the Composition Modes to draw the second image on top (or the other way around). Make sure to convert the images to ARGB32 before using them.
To make the inner Part of the Circle transparent you can adjust the Alpha Channel accordingly.
Here is a small Example using Composition mode:
QPainter p(&imageCircle);
p.setCompositionMode(QPainter::CompositionMode_SourceOver);
p.drawImage(image);
p.end()
Here you can find the Qt Documentation of QPainter.

How to draw a QPixmap with transparency

I've got a QPixmap and I would like to draw it on a QWidget. However, I would like to make it 50% transparent so that the background can be seen below. How can I do that?
You set the compositionmode in the QPainter and then either use a mask to define which bits of the iage are transparent or use QImage::Format_ARGB32_Premultiplied type for the image with the alpha channel set.
See the example http://doc.qt.io/archives/4.6/demos-composition.html

Qt mouse cursor transparency

I would like to change the stock cursor with a translucent one, a simple filled circle, of various sizes, depending on the level of zoom in the underlying widget (say, RGBA = 200, 200, 200, 128).
Is this at all possible with Qt? If not, is it a limitation in Qt or the underlying libs? Do you have suggestions as to how this could be accomplished by other means, e.g., hiding the cursor and overlaying a transparent pixmap at the cursor position (albeit slower)? TIA
QCursor can take a QPixmap which does support alpha channel. So I don't see why it can't be done.
I just figured this out for a project of my own. I did it with this code in the constructor of the relevant widget:
m_LPixmap = new QPixmap(32,32);
m_LPixmap->fill(Qt::transparent); // Otherwise you get a black background :(
QPainter painter(m_LPixmap);
QColor red(255,0,0,128);
painter.setPen(Qt::NoPen); // Otherwise you get an thin black border
painter.setBrush(red);
painter.drawEllipse(0,0,32,32);
m_Cursor = QCursor(*m_LPixmap);
setCursor(m_Cursor);

Resources