Solved Cannot create transparent pixmap for QDrag
-
Hello,
I'm trying to set the pixmap of a QDrag to a transparent pixmap but I keep getting a white background in it (qt version 4.8.6). Specifically I render an item and its children to a pixmap which I then use on a QDrag. Here is the code:
void drawItemRecursive(QGraphicsItem* item, QPainter& painter) { painter.translate(item->pos()); item->paint(&painter, nullptr, nullptr); for (QGraphicsItem* child : item->childItems()) { drawItemRecursive(child, painter); } painter.translate(QPointF(-item->pos().x(), -item->pos().y())); } QPixmap View::toPixmap() { QRectF rect = QRect(0, 0, size().width(), size().height()); if (rect.isNull() || !rect.isValid()) { return QPixmap(); } // Create the pixmap QPixmap pixmap(size().toSize()); pixmap.fill(Qt::transparent); QPainter painter(&pixmap); painter.setRenderHints(QPainter::Antialiasing | QPainter::SmoothPixmapTransform | QPainter::HighQualityAntialiasing, true); painter.setPen(QPen(QBrush(Qt::transparent), 0)); painter.setBrush(QBrush(Qt::transparent)); painter.setBackgroundMode(Qt::BGMode::TransparentMode); painter.setCompositionMode(QPainter::CompositionMode_Plus); paint(&painter, nullptr, nullptr); for (QGraphicsItem* child : childItems()) { painter.save(); drawItemRecursive(child, painter); painter.restore(); } painter.end(); return pixmap; }
Then when I'm about to drag the item I do:
auto drag = new QDrag(event->widget()); auto pixmap = toPixmap(); drag->setPixmap(pixmap);
But it always has a white background. I've tried adding this line in the code
pixmap.setMask(pixmap.createHeuristicMask());
following the robot drag n drop example which seems to be removing the white background and making the pixmap transparent, but it also stretches it a little bit and the bottom of it seems a bit distorted.Does anyone have any ideas of what might be going wrong?
-
I've found the solution. I had to patch qt source code to get this working. Here is the patch for anyone else struggling with this:
--- qt.old/src/gui/kernel/qdnd_qws.cpp 2019-07-04 02:22:03.051763167 +0300 +++ qt/src/gui/kernel/qdnd_qws.cpp 2019-07-04 02:22:36.895605031 +0300 @@ -97,6 +97,7 @@ // setAttribute() should be done unconditionally! if (QApplication::type() == QApplication::GuiServer) setAttribute(Qt::WA_TransparentForMouseEvents); + setAttribute(Qt::WA_TranslucentBackground); } void setPixmap(QPixmap pm) --- qt.old/src/gui/kernel/qdnd_x11.cpp 2019-07-04 02:22:54.539523527 +0300 +++ qt/src/gui/kernel/qdnd_x11.cpp 2019-07-04 02:22:12.647718085 +0300 @@ -286,6 +286,7 @@ | Qt::BypassGraphicsProxyWidget) { setAttribute(Qt::WA_X11NetWmWindowTypeDND); + setAttribute(Qt::WA_TranslucentBackground); } void setPixmap(const QPixmap &pm)
-
Hi,
Did you try to have that transparent background while doing simple base painting ?
-
@SGaist Hello again and sorry for the delayed response. I just tested this code and it works outside a QDrag. I also had to remove these two lines:
painter.setBackgroundMode(Qt::BGMode::TransparentMode); painter.setCompositionMode(QPainter::CompositionMode_Plus);
they seem to be making the pixmap a bit grey. Not sure why but if I remove them and just call the toPixmap() function and then use the returned pixmap on a test item it works as expected (no white background). On the other hand if I use it on a QDrag then I get the same pixmap but with a white background. Here is the drag code (runs on a mouse move after a long press):
auto pixmap = toPixmap(); // do drag n drop auto drag = new QDrag(event->widget()); QByteArray data; QDataStream stream(&data, QIODevice::WriteOnly); QString strData = QString::number(row()) + ":" + QString::number(column()); stream << strData; QMimeData* mimeData = new QMimeData(); mimeData->setData("application/modelCellData", data); drag->setMimeData(mimeData); drag->setPixmap(pixmap); drag->setHotSpot(QPoint(halfSize().width(), halfSize().height()));
In the test item btw the pixmap is drawn in the paint method like so:
if (!m_pixmap.isNull()) { QRectF rect = boundingRect(); painter->setRenderHints(QPainter::Antialiasing | QPainter::HighQualityAntialiasing, true); painter->setBrush(QBrush(QColor(Qt::transparent))); painter->setPen(QPen(QBrush(QColor(Qt::transparent)), 0)); painter->drawPixmap(rect.x(), rect.y(), rect.width(), rect.height(), m_pixmap); }
It looks to me like some sort of blending issue (hence why I was trying those composition and background modes) between the pixmap's or painter's background and whatever I draw on it. But can't figure out what exactly. And then again why would it behave differently when I simply draw the result pixmap and when I use it in a QDrag.
-
What OS are you running ?
What version of Qt are you using ? -
This is happening both on my dev machine which is running:
Ubuntu 18.04.1 LTS
as well as on the target board which is running:
NAME=Buildroot
VERSION=2015.02
ID=buildroot
VERSION_ID=2015.02
PRETTY_NAME="Buildroot 2015.02"
I am using
Qt version 4.8.6
on both of them.Worth mentioning as its already shown here that I'm using buildroot for the target board OS and from what I've read in other posts its a PITA if at all possible to replace the Qt version on it (https://stackoverflow.com/questions/50024991/how-to-tell-buildroot-to-use-a-different-version-of-source-code-of-qt). So if this is a Qt issue in this specific version and not wrong usage on my side I would really like to patch it if possible instead of upping the version.
Also I did try using Qt5 as there is an option in buildroot in
menuconfig
and used bare bones Qt with just the addition of PNG support and that resulted in a kernel panic. So it does seem like it will be a painful experience if I do indeed have to go down that route. -
Probably worth noting that even if I just do this:
QPixmap pixmap(size().width(), size().height()); pixmap.fill(Qt::transparent); ... drag->setPixmap(pixmap);
I still get a white pixmap. On both OS's. So this doesn't seem related to my
toPixmap()
function at all. -
Are you using your own build of Qt ?
-
@SGaist No. On my dev machine I use open source qt that I installed either via
apt-get install
or by downloading the package and installing it. Can't remember which of the two but I certainly didn't build it manually. And on the board I use buildroot as mentioned already. Obviously, for the board build buildroot downloads and builds it. But I have not applied any patches on that so far either. -
Sorry for the downvote on your previous post btw but the answer to one of your questions is already mentioned in my original question (i.e. qt version 4.8.6).
-
@Boofish said in Cannot create transparent pixmap for QDrag:
Sorry for the downvote on your previous post btw but the answer to one of your questions is already mentioned in my original question (i.e. qt version 4.8.6).
While I did miss you wrote the Qt version, the OS you are using is still legitimate, especially if you are using different flavours of Linux.
Note that you are not even using the latest version of the Qt 4 series and also it has reached end of life a long time ago now.
-
@SGaist Retracted the downvote. But anyway I would still like to fix the issue on this qt version preferably, for the reason I mentioned. I mean I'd like to identify the actual problem so if anyone knows what the bug is if it is indeed a bug, I can surely patch it. Also when you say "it has reached end of life a long time ago now" do you mean Qt4.8.6 or Qt4 in general?
-
Qt 4. There won't be any new bug fixes release unless there's a highly critical security issue. See here.
One thing you can still try is Qt 4.8.7 if you can't update to a recent supported version of Qt.
-
Thanks for the responses. I'll try upping the version. I'll also dig into the code a bit more because the drag n drop robot example... works. Which is suspicious. And that is also using a pixmap in a QDrag from what I see.
-
I'm going to leave this open in case I do find a solution, be it upping the version or whatever else (a quick google search shows that I'm not the only one that has had this issue or similar issues). I'll post it if I do maybe it will be helpful to someone else.
-
One thing that could help is to provide a minimal compilable example that reproduces that. So other people may have a look at it more easily.
-
I've found the solution. I had to patch qt source code to get this working. Here is the patch for anyone else struggling with this:
--- qt.old/src/gui/kernel/qdnd_qws.cpp 2019-07-04 02:22:03.051763167 +0300 +++ qt/src/gui/kernel/qdnd_qws.cpp 2019-07-04 02:22:36.895605031 +0300 @@ -97,6 +97,7 @@ // setAttribute() should be done unconditionally! if (QApplication::type() == QApplication::GuiServer) setAttribute(Qt::WA_TransparentForMouseEvents); + setAttribute(Qt::WA_TranslucentBackground); } void setPixmap(QPixmap pm) --- qt.old/src/gui/kernel/qdnd_x11.cpp 2019-07-04 02:22:54.539523527 +0300 +++ qt/src/gui/kernel/qdnd_x11.cpp 2019-07-04 02:22:12.647718085 +0300 @@ -286,6 +286,7 @@ | Qt::BypassGraphicsProxyWidget) { setAttribute(Qt::WA_X11NetWmWindowTypeDND); + setAttribute(Qt::WA_TranslucentBackground); } void setPixmap(const QPixmap &pm)
-
@boofish If this is really a Qt issue and you have a patch you should contribute it to Qt, so it gets integrated.
-
@jsulm Hi jsulm, this is on qt 4.8. I don't think this file even exists in the latest qt version.