Qt opacity color brush? - qt

Particular in my case, I want to paint a line to a QGraphicsScene using adLine(). Befor that I have paint something on the scene and I want the last big line on the top of all of these but i still can see what I already paint.
In general, can I paint an Item and fill it with that kind of color which I can see what under the Item?
I have read some thing about BGMode here: http://doc.qt.io/qt-5/qt.html#BGMode-enum but I not sure how it work.

When you call addLine, you pass in a QPen. If you want that pen to draw with a semi-transparent color (so that things "beneath" still show), initialize that QPen with a color with an alpha-channel value below 255. (See QColor.)
QPen transRed(QColor(0xFF, 0, 0, 0x80));
scene.addLine(x1,y1, x2,y2, transRed);

Related

QPainter drawing lines - configuring line softness (horizontal opacity gradient)

I am looking for a way to apply a horizontal opacity gradient when painting QLine elements using QPainter. Put simply, I want to be able to have the line opacity decrease the further away from the line center it is being painted. The effect I want to achieve corresponds to what a lot of image editing tools comonly describe as hardness of a brush.
Here is a sample image that compares a line using a hard brush to a soft one:
This would be a minimum example for painting a regular QLine:
QPainter p;
p.setPen(QPen(Qt::black, 12, Qt::SolidLine, Qt::RoundCap));
p.drawLine(QPointF(0,0), QPointF(1024,1024));
How and where would I configure the line hardness I am describing? Is there something like a fall-off property when painting QLine elements?
In the docs I could only find examples for how to apply linear gradients between set points, which is not what I am looking for.
That's not QPen painting, that's brush painting, like in say photoshop, and Qt doesn't really support such functionality out of the box.
But it is quite easy to implement, you need a brush stencil pixmap, and you simply draw that pixmap on your target paint device along a line at a given step.
The line interpolation part is already answered here.
It is recommended that the brush stencil is an 8 bit grayscale QImage, then you can easily get a colorized version of that by using the greyscale value as an alpha value for the solid color of choice. QImage is preferable, as it offers individual pixel access. This allows to have any type of brush aside from hard and soft, including certain artistic brushes.
Naturally, if all you need is a soft brush, you can generate that directly in the desired color by utilizing Qt's existing gradients and skip the stencil colorizing part. You can use QPainter to procedurally draw colorizable or full color stencils to use as a brush.

Qt: Why does my paintEvent() erase everything before doing its job?

I'm trying to make my widget paint a rectangle with every paintEvent it receives. The rectangles are supposed to increase in size by 1px at a time, filling a square. What I get, however, is only the latest (and largest) rectangle.
void TestClass::paintEvent(QPaintEvent* e){
static int size = 1;
QStylePainter painter(this);
painter.setPen(Qt::blue);
painter.drawRect(QRect(50, 50, size, size));
size++;
}
I don't understand why it would be that way. I expected the painter to just paint on top of what is already there. Instead it seems to delete the previously drawn rectangle, leaving me with a single rectangle at any time. Any ideas?
setAutoFillBackground(true/false) does not change anything but the color of the background.
To evoke a paintEvent I update() inside mousePressEvent(). So my rectangles grow with every click.
Thanks a lot.
So, to answer my own question, I found out that:
(1) update(QRect area) erases the area specified by its argument before doing anything else. Calling update without argument erases the whole widget area.
(2) The area that has been cleared is the only area that any painting is done on, even if your paintEvent() looks to paint somewhere else. The untouched part of the widget is not affected.
For example, consider this paintEvent().
void myWidget::paintEvent(QPaintEvent* e){
QPainter painter(this);
static int counter = 1;
if (counter % 2){
painter.fillRect(0, 0, 199, 199, Qt::blue); //Fill with blue color
} else {
painter.fillRect(0, 0, 199, 199, Qt::green); //Fill with green color
}
counter++;
}
Calling update() repeatedly will toggle between green and blue color for every pixel. However, upon calling update(QRect(0, 0, 50, 50)) only the top left quarter of the widget's area will change its color, the other pixels will remain untouched, even if paintEvent(..) contains the instruction to always paint over the whole widget's area.
I do not know whether my answer is fully correct under any circumstances, but I expect more noobs to be confused about the relationship between update() and paintEvent() and so I'll offer this as a first aid.
Greets.
The QWidget::paintEvent docs state that
When the paint event occurs, the update region has normally been
erased, so you are painting on the widget's background.
So, probably that's the case in your example.
You're not guaranteed any sort of state preservation between invocations of paintEvent. That's the long and the short of it. The only correct semantics of your implementation of paintEvent are: paint (at least) the entire region that was passed to you, as in: touch every pixel, unless your widget was pre-cleared prior to painting.

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.

Problem with QWidget borders in a QGridLayout

I have a QGridLayout filled with my custom QWidgets (I'll call them CellWidgets). I want to display a grid between all of the CellWidgets so the columns and rows are clearly visible.
Obviously this isn't done from QGridLayout, as that is simply a holder for widgets that draw themseleves. I made my CellWidgets draw a border by over-riding the paintEvent function like so:
QPainter Painter(this);
Painter.setPen(QPen(QBrush(Qt::white), 2));
Painter.setBrush(Qt::black);
Painter.drawRect(0, 0, width(), height());
The QGridLayout spacing is set to 0, however, when it is drawn the grid border has a single width around the edges and double that width between cells, as the border of the cell is effectively being displayed twice.
Any clean way to solve/avoid this problem?
I think you are heading in the wrong direction.
Instead of painting your widget you should try to change the background color of parent widget to get the effect that you want.
Check out this link for an example.
I hope this helps.

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