Qt- Change opacity of QPixmap - c++

How to change opacity of QPixmap?
I've set an image as background actually I want to change its opacity, Here is my code:
Call.h:
private:
QPixmap m_avatar;
Call.cpp:
void Call::resizeEvent(QResizeEvent *e)
{
QPalette pal = palette();
pal.setBrush(backgroundRole(), m_avatar.scaled(e->size(), Qt::IgnoreAspectRatio, Qt::SmoothTransformation));
setPalette(pal);
}
I've changed resizeEvent function, but it doesn't change background's opacity.
void Call::resizeEvent(QResizeEvent *e)
{
QPixmap result_avatar(m_avatar.size());
result_avatar.fill(Qt::transparent);
QPainter painter;
painter.setOpacity(0.5);
painter.begin(&result_avatar);
painter.drawPixmap(0, 0, m_avatar);
painter.end();
QPalette pal = palette();
pal.setBrush(backgroundRole(), result_avatar.scaled(e->size(), Qt::IgnoreAspectRatio, Qt::SmoothTransformation));
setPalette(pal);
}
Any suggestion?

You are not using local QPainter object. According to QWidget Events:
paintEvent() is called whenever the widget needs to be repainted.
Every widget displaying custom content must implement it. Painting
using a QPainter can only take place in a paintEvent() or a function
called by a paintEvent().
Here it works:
void Call::paintEvent(QPaintEvent *)
{
// create a new object scaled to widget size
QPixmap result_avatar = m_avatar.scaled(size());
QPainter painter(this);
painter.setOpacity(0.5);
// use scaled image or if needed not scaled m_avatar
painter.drawPixmap(0, 0, result_avatar);
}
Update for paiting on pixmap case
If it is needed only to paint with some opacity on a pixmap using QPainter, the opacity must be set only after QPainter activation by QPainter::begin(). So, after changing the order the pixmap result_avatar has two images (one resized with opacity 1 and original pixmap on top with opacity 0.5):
QPainter painter;
painter.begin(&result_avatar);
painter.setOpacity(0.5);
painter.drawPixmap(0, 0, m_avatar);
painter.end()

Related

QT - pixmap artefacts on drag

I have an issue with pixmaps created for drag events. For drag events of my derived QGraphicsRectItem I create a semi-transparent pixmap from that item.
In the debug build everything looks fine.
But in the release build the drag pixmap has some periodic and random artefacts
here is the code:
QPixmap MyGraphicsRectItem::toPixmap() const
{
QRect r = boundingRect().toRect();
QPixmap pixmap(r.width(), r.height());
QColor dragColor(color);
dragColor.setAlphaF(0.5);
QPainter painter;
painter.begin(&pixmap);
painter.fillRect(pixmap.rect(), dragColor);
painter.setPen(Qt::white);
QFont font("SegoeUI");
font.setBold(true);
painter.setFont(font);
painter.drawText(pixmap.rect(), QString(" ") + textItem->toPlainText());
if (pixItem != nullptr) {
painter.setOpacity(0.5);
painter.drawPixmap(pixItem->pos(), pixItem->pixmap());
}
painter.end();
return pixmap;
}
Could that be a kind of memory issue?
The QPixmap is initialized with uninitialized data. In Debug, this is often set to a fixed pattern, but in Release it is garbage.
You should fill the pixmap with transparent color before using it.
QPixmap::QPixmap(int width, int height)
Constructs a pixmap with the given width and height. If either width or height is zero, a null pixmap is constructed.
Warning: This will create a QPixmap with uninitialized data. Call fill() to fill the pixmap with an appropriate color before drawing onto it with QPainter.
(From Qt Docs)

QT5: Drawing rect on top of another rect using drawPixMap()

am I using drawPixmap() correctly?
Essentially my goal is to take an tileset image, and replace an individual tile with a custom tile image.
I'm able to get both images to load on the screen, but when I call drawPixmap(), then original image doesn't change at all.
Thanks in advance.
void replaceCustomTile(QPixmap custom, QPixmap target, int whichTile) {
QRect rect(0, 0 + (squareTileSize * whichTile), squareTileSize, squareTileSize);
QRect customRect = custom.rect();
QPainter painter(this);
painter.drawPixmap(rect, target, customRect);
painter.end();
}
EDIT:
This is how replaceCustomTile is called:
QPixmap terrainTiles(":/static/Terrain.png");
QPixmap customTile(":/static/Smiles.png");
replaceCustomTile(customTile, terrainTiles, 0);
To intialize QPainter by this it must be called from the widget paintEvent(QPaintEvent *) if you want to draw it on some widget. So, replaceCustomTile() should be called from the event handler in that case.
To draw some pixmap on top of another pixmap QPainter should be initialized by the target pixmap using QPainter::begin():
QPainter painter;
painter.begin(&target);
painter.drawPixmap(rect, custom);
painter.end();
The above code draws QPixmap custom into given QRect rect over QPixmap target. The target is modified.

can I reuse the QPainter?

Rendering to bitmap, I have to create a QPainter. If I have to render multiple areas to multiple bitmaps, how do I reset the QPainter ?
QImage img1(scene1.sceneRect().size().toSize(), QImage::Format_ARGB32_Premultiplied);
img1.fill(Qt::color0);
QPainter painter1(&img1);
painter1.setRenderHint(QPainter::Antialiasing);
scene1.render(&painter1);
painter1.end();
QImage img2(scene2.sceneRect().size().toSize(), QImage::Format_ARGB32_Premultiplied);
img2.fill(Qt::color0);
QPainter painter2(&img2);
painter2.setRenderHint(QPainter::Antialiasing);
scene2.render(&painter2);
painter2.end();
How can I reuse the painter ? am I getting performance hits/higher memory usage by creating a new QPainter for each scene / image ?
Trying
QImage img(scene1.sceneRect().size().toSize(), QImage::Format_ARGB32_Premultiplied);
img.fill(Qt::color0);
QPainter painter(&img);
painter.setRenderHint(QPainter::Antialiasing);
scene1.render(&painter);
painter.end();
img.save("img.png");
img = QImage(scene2.sceneRect().size().toSize(), QImage::Format_ARGB32_Premultiplied);
img.fill(Qt::color0);
painter = QPainter(&img);
painter.setRenderHint(QPainter::Antialiasing);
scene2.render(&painter);
painter.end();
I get errors of the type
error: 'QPainter& QPainter::operator=(const QPainter&)' is private
You can reuse your QPainter with the following syntax:
QPainter painter;
painter.begin( &img1 );
...
painter.begin( &img2 );
...
But you can only use one QPainter for one QPaintDevice (in this case an image).
Read this.
It appears that QObject and Classes derived from it, as well as QPainter and maybe other classes, have private constructors (??? why)
So...
QImage img(scene1.sceneRect().size().toSize(), QImage::Format_ARGB32_Premultiplied);
img.fill(Qt::color0);
QPainter* painter = new QPainter(&img);
painter->setRenderHint(QPainter::Antialiasing);
scene1.render(painter);
painter->end();
img.save("img.png");
img = QImage(scene2.sceneRect().size().toSize(), QImage::Format_ARGB32_Premultiplied);
img.fill(Qt::color0);
painter = new QPainter(&img);
painter->setRenderHint(QPainter::Antialiasing);
scene2.render(painter);
painter->end();
delete painter;
I was writing this as vizhanyolajos was posting his answer, and I think I prefer that answer.
You do NOT need to write this:
QPainter* painter = new QPainter( &img );
you can write this instead:
QPainter painter( &img );
with this you don't have to think about the deleting of the obejct.
Yes, all the QObject derived classes have private copy constructors. You can read about the reasons here.
I think you do not need to worry about the reusing of the QImage. You can instantiate a new instance and use the being( ... ) function of the QPainter class.

Qt drawRect in background

I want to paint the background of a slider. I tried this but the color covers up the whole slider. This is in an inherited class of QSlider
void paintEvent(QPaintEvent *e) {
QPainter painter(this);
painter.begin(this);
painter.setBrush(/*not important*/);
// This covers up the control. How do I make it so the color is in
// the background and the control is still visible?
painter.drawRect(rect());
painter.end();
}
To set the background of a widget you could set the style sheet:
theSlider->setStyleSheet("QSlider { background-color: green; }");
The following will set the background of the widget, allowing you to do more:
void paintEvent(QPaintEvent *event) {
QPainter painter;
painter.begin(this);
painter.fillRect(rect(), /* brush, brush style or color */);
painter.end();
// This is very important if you don't want to handle _every_
// detail about painting this particular widget. Without this
// the control would just be red, if that was the brush used,
// for instance.
QSlider::paintEvent(event);
}
And btw. the following two lines of your sample code will yield a warning:
QPainter painter(this);
painter.begin(this);
Namely this one using GCC:
QPainter::begin: A paint device can only be painted by one painter at
a time.
So make sure, as I do in my example, that you either do QPainter painter(this) or painter.begin(this).

QPixmap of a QGraphicsTextItem

How do you convert/paint a QGraphicsTextItem into a QPixmap?
You can add it to a QGraphicsScene (if it's not already inside one) and then render() the scene to a QPixmap using a QPainter
QPixmap pix(100, 100);
QPainter paint(&pix);
scene.render(&paint);
Or, you can save yourself the trouble and just use QPainter::drawText() after changing the current font of the painter. it should provide the same capabilities.
Maybe something like this-
QPixmap pix(100, 100);
QPainter paint(&pix);
paint.drawText(0, 0, "Hello World");
The QGraphicsTextItem::document() function is the back door you're looking for:
// pItem is a QGraphicsTextItem *
QPixmap srcPixmap(pItem->boundingRect().size().toSize());
QPainter tmpPainter(&srcPixmap);
pItem->document()->drawContents(&tmpPainter);
tmpPainter.end()