I'm working on a painter-like application. The idea is to have two pixmaps. First contains original image, uploaded by user, and second contains all the drawing and has transparent background. To show result pixmaps are to be combined and shown in QLabel. It's done like so:
Uploading and image and creating transparent pixmap with the same size
void ImageViewer::on_openAct_triggered()
{
QString fileName = QFileDialog::getOpenFileName(this,
tr("Open File"), QDir::currentPath());
if (!fileName.isEmpty()) {
QImage image(fileName);
if (image.isNull()) {
QMessageBox::information(this, tr("Image Viewer"),
tr("Cannot load %1.").arg(fileName));
return;
}
imageLabel->setPixmap(QPixmap::fromImage(image));
scaleFactor = 1.0;
objectpix.scaled(QSize(imageLabel->size()), Qt::KeepAspectRatio, Qt::FastTransformation);
objectpix.fill(Qt::transparent);
/.../
}
}
Getting mouse coordinates, drawing on a second pixmap and combining first and second one
mFirstX = e->x()/scaleFactor+ scrollArea->horizontalScrollBar()->value()/scaleFactor;
mFirstY = (e->y() - 31)/scaleFactor+ scrollArea->verticalScrollBar()->value()/scaleFactor;
/.../
QPainter paint(&objectpix);
QPen PointPen (Qt::red);
PointPen.setWidth(5);
QBrush PointBrush (Qt::red,Qt::SolidPattern);
QPoint p1 = QPoint(mFirstX,mFirstY);
paint.setPen(PointPen);
paint.setBrush(PointBrush);
paint.drawEllipse(p1,2,2);
QPixmap p(*imageLabel->pixmap());
QPainter painter(&p);
painter.drawPixmap(imageLabel->rect(),objectpix,objectpix.rect());\
painter.end();
imageLabel->setPixmap(p);
But nothing is shown that way. If i show only second pixmap(which is to contain all the drawings and have transparent background) it only shows transparent pixmap i.e i see background of my application. What am i doing wrong? Any help is appreciated.
Somehow I had the feeling what OP descibes should actually be possible...
...and tried on my own.
This is what I got (testQPixmapCombine.cc
):
#include <QtWidgets>
class Label: public QLabel {
private:
QPixmap _qPixmap;
public:
Label(QWidget *pQParent = nullptr):
QLabel(pQParent)
{ }
virtual ~Label() = default;
Label(const Label&) = delete;
Label& operator=(const Label&) = delete;
void setPixmap(const QPixmap &qPixmap)
{
_qPixmap = qPixmap;
QLabel::setPixmap(_qPixmap = qPixmap);
}
protected:
virtual void mousePressEvent(QMouseEvent *pQEvent) override;
};
void Label::mousePressEvent(QMouseEvent *pQEvent)
{
// clear overlay
QPixmap qPixmapDraw(_qPixmap.size());
qPixmapDraw.fill(QColor(0, 0, 0, 0));
// draw red circle at mouse coordinates
{ QPainter qPainter(&qPixmapDraw);
qPainter.setPen(QPen(Qt::red, 2));
qPainter.drawEllipse(pQEvent->pos(), 20, 20);
}
// combine pixmaps
QPixmap qPixmapComp = _qPixmap;
{ QPainter qPainter(&qPixmapComp);
qPainter.drawPixmap(0, 0, qPixmapDraw);
}
QLabel::setPixmap(qPixmapComp);
pQEvent->accept();
}
int main(int argc, char **argv)
{
qDebug() << "Qt Version:" << QT_VERSION_STR;
QApplication app(argc, argv);
// load image file
const QImage qImg("cat.png");
QPixmap qPixmap;
qPixmap.convertFromImage(qImg);
// setup UI
Label qWin;
qWin.setWindowTitle(QString::fromUtf8("Combine Pixmaps"));
qWin.setPixmap(qPixmap);
qWin.show();
// runtime loop
return app.exec();
}
and the corresponding Qt project (testQPixmapCombine.pro
):
SOURCES = testQPixmapCombine.cc
QT += widgets
I compiled and tested in cygwin64:
$ qmake-qt5 testQPixmapCombine.pro
$ make && ./testQPixmapCombine
g++ -c -fno-keep-inline-dllexport -D_GNU_SOURCE -pipe -O2 -Wall -W -D_REENTRANT -DQT_NO_DEBUG -DQT_WIDGETS_LIB -DQT_GUI_LIB -DQT_CORE_LIB -I. -isystem /usr/include/qt5 -isystem /usr/include/qt5/QtWidgets -isystem /usr/include/qt5/QtGui -isystem /usr/include/qt5/QtCore -I. -I/usr/lib/qt5/mkspecs/cygwin-g++ -o testQPixmapCombine.o testQPixmapCombine.cc
g++ -o testQPixmapCombine.exe testQPixmapCombine.o -lQt5Widgets -lQt5Gui -lQt5Core -lGL -lpthread
Qt Version: 5.9.4
There is a little red circle at the bottom of image which appeared after I clicked on the bolt.
I must admit, concerning my code, I even hadn't needed an extra QPixmap
. (I wanted to demonstrate that drawing with a transparent pixmap works as expected – according to OPs question.)
This alternative implementation of Label::mousePressEvent()
would have produced the same effect:
void Label::mousePressEvent(QMouseEvent *pQEvent)
{
QPixmap qPixmapDraw(_qPixmap);
// draw red circle at mouse coordinates
{ QPainter qPainter(&qPixmapDraw);
qPainter.setPen(QPen(Qt::red, 2));
qPainter.drawEllipse(pQEvent->pos(), 20, 20);
}
QLabel::setPixmap(qPixmapDraw);
pQEvent->accept();
}
Please note, that I considered what was raised as potential issue in Kerndog73's answer: Scoping the QPainter qPainter
with an extra pair of curly braces, I achieved the same effect as noted in the doc. of QPainter::end()
:
Ends painting. Any resources used while painting are released. You don't normally need to call this since it is called by the destructor.
(Emphasize – mine.)