Unsolved Dragging out to non-Qt desktop
-
Hello,
I’m working on dragging and dropping capability in my desktop app, which consists of multiple QWidget.
D&D works OK if it’s internal movement where the drop receiver is another QWidget.
My question is how can I achieve the same functionality between the desktop app and non Qt app such as Window desktop where no qt app exists.
How and where can I handle the dropEvent outside of Qt?Many thanks in advance for your help.
Sat -
@ShinSat
your question is very unclear.How and where can I handle the dropEvent outside of Qt?
You shouldn't and you wont handle the drop outside your application. Similar to a copy and aste via clipboard you simply provide data to the operating system and let it do the multi-window drag-handling. The final target application which receives the drop handles the data on it's own.
The only result you get is when your QDrag::exec() returnes and check the returned drop result. -
Hi
To drop to desktop, you must follow windows rules for the mimedata
else it wont accept.This sample drags file from Qt to desktop / explorer
It uses a native windows header. (#include <Shlobj.h>)#include "mainwindow.h" #include <QApplication> #include <QtGui> #include <Shlobj.h> class Widget : public QWidget { void mousePressEvent(QMouseEvent* e) { QPoint hotSpot = e->pos(); QList<QUrl> strList; FILEGROUPDESCRIPTOR fgd; FILEDESCRIPTOR fd[ 1 ]; strList.append( QUrl( "http://www.qt.io/" ) ); fgd.cItems = 1; fgd.fgd[ 0 ].dwFlags = FD_PROGRESSUI; wcscpy( fgd.fgd[ 0 ].cFileName, L"qtrules.url" ); QMimeData* mimeData = new QMimeData; mimeData->setText("www.gaspar.net"); mimeData->setUrls( strList ); mimeData->setData("text/plain", QByteArray( "http://www.gaspar.net" ) ); mimeData->setData("text/html", QByteArray( "<!--StartFragment--><a href=\"http://www.gaspar.net\">The Gaspar Website</a><!--EndFragment-->" ) ); mimeData->setData("FileName", QByteArray( "Gaspar Website.url" ) ); mimeData->setData("FileGroupDescriptorW", QByteArray::fromRawData( ( const char* )&fgd, sizeof ( FILEGROUPDESCRIPTOR ) ) ); mimeData->setData("FileContents", QByteArray( "[InternetShortcut]\r\nURL=http://www.gaspar.net" ) ); QPixmap pixmap(":/images/imagelists/16x16/webpage.png"); render(&pixmap); QDrag* drag = new QDrag(this); drag->setMimeData(mimeData); drag->setPixmap(pixmap); drag->setHotSpot(hotSpot); Qt::DropAction dropAction = drag->exec(Qt::CopyAction | Qt::MoveAction, Qt::CopyAction); if (dropAction == Qt::MoveAction) { update(); } } }; int main(int argc, char* argv[]) { QApplication app(argc, argv); Widget window; window.show(); return app.exec(); }
Credits goes to http://www.gaspar.net/oteqmimewindows.html
-
@mrjj
There should be a "Code Snippets" forum here, and this kind of post could be put there with a decent title. -
@JNBarchan
Yes, that would be great. I think we might be able to use the wiki for it since it already has samples. -
@mrjj
Just a note: File drags to desktop can also be achieved using Qt classes only:- start a drag containing all the needed mime-types
- create an empty QTemporaryFile with the target file-name and set it's file path to the mime-data (file-urls type)
- fill the temporary file once it is requested in the QMimeData::retrieveData() method (see the delayed encoding example)
- the OS copies the (temp-)file to the drop-position
-
Did you try delayed encoding sample ?
The sample will not work for me on win 7 or win 10.
Tried 2 pc. Desktop/explorer wont accept.So i wonder if issue with my pcs or just dont work like that in newer Windows.
-
@mrjj
yes, but it's a while ago. I will give it a try. -
Super. Maybe i just do it wrong.
I drag the export Button out from window. It show red stop sign. -
@mrjj
the following (unoptimized code) works (Qt 5.9, Windows 7):MimeData::MimeData() : QMimeData() { QString filePath = QStandardPaths::writableLocation(QStandardPaths::TempLocation) % QDir::separator() % "Gaspar Website.url"; m_File = new QFile( filePath, this ); } MimeData::~MimeData() { if( m_File && m_File->isOpen() ) m_File->close(); } QStringList MimeData::formats() const { return QMimeData::formats() << QLatin1String("text/uri-list"); } QVariant MimeData::retrieveData(const QString &mimeType, QVariant::Type type) const { if( mimeType == QStringLiteral("text/uri-list") ) { // since this method may be called multiple during a single drag it's not necessary to also write to the file multiple times -> needs optimization if( m_File->open(QFile::WriteOnly) ) { m_File->write( QByteArray("[InternetShortcut]\r\nURL=http://www.gaspar.net") ); m_File->close(); } return QVariant::fromValue<QUrl>( QUrl::fromLocalFile(QFileInfo(*m_File).absoluteFilePath()) ); } else return QMimeData::retrieveData(mimeType, type); }
Although it seems there are some caveats:
- it stopped working when i set the path of the temp file into a subfolder in the temp-dir ... o.O
- the
retrieveData()
always requests the data with the typeQVariant::QVariantList
. But still it only works when i return a QUrl (not a QList) packed into the variant data.
Very strange.
-
Good work.
Ehh so it likes only root of tmp dir ?? odd
2: that is a bit odd but i guess it was only ment for 1 file then.Would it be possible to get the test code ?
Want to see if win 10 likes it also :)This is nicer than the platform bound i found :) \o/
-
@mrjj said in Dragging out to non-Qt desktop:
Would it be possible to get the test code ?
thats actually all the code (despite the obvious header file).
All i did additionally for testing was this:
void MainWindow::mousePressEvent(QMouseEvent *event) { event->accept(); MimeData* mimeData = new MimeData; QDrag drag( this ); drag.setMimeData(mimeData); drag.exec(Qt::CopyAction); }
the mime type is
text/uri-list
, so a list does make sense. It also makes sense to copy multiple files at once to a folder in the filesystem explorer.
I have no idea why it's not working. Would need to debug into Qt source code to make sure.