I want to achieve a drag and drop from my application to the OS window system (Windows 10), but not by using the mouse. Instead, the content will be selected by a button press and should automatically be drag-dropped to the window under the mouse cursor.
I wrote a test class, for a regular drag-drop with the mouse, and for the same with a key press:
#include <QtCore/QList>
#include <QtCore/QUrl>
#include <QtCore/QMimeData>
#include <QtWidgets/QApplication>
#include <QtWidgets/QMainWindow>
#include <QtGui/QDrag>
#include <QtGui/QKeyEvent>
#include <QtGui/QMouseEvent>
#include <QtGui/QScreen>
void move_file() {
mime_data->setUrls(QList<QUrl> { } << m_file);
QDropEvent drop_event
{ mouse_pos, Qt
::MoveAction, mime_data, Qt
::NoButton, Qt
::NoModifier };
}
protected:
switch (e->key()) {
case Qt::Key_M:
move_file();
break;
default:
}
}
mime->setUrls(QList<QUrl> { } << m_file);
auto* drag
= new QDrag { this };
drag->setMimeData(mime);
drag->exec();
}
public:
DragDropTester
(const QString
& path
) : QMainWindow { } { m_file
= QUrl::fromLocalFile(path
);
setFixedSize(400, 400);
show();
}
};
#include <QtCore/QList>
#include <QtCore/QUrl>
#include <QtCore/QMimeData>
#include <QtWidgets/QApplication>
#include <QtWidgets/QMainWindow>
#include <QtGui/QDrag>
#include <QtGui/QKeyEvent>
#include <QtGui/QMouseEvent>
#include <QtGui/QScreen>
class DragDropTester: public QMainWindow {
QUrl m_file;
void move_file() {
auto* mime_data = new QMimeData;
mime_data->setUrls(QList<QUrl> { } << m_file);
auto* screen = QApplication::primaryScreen();
auto mouse_pos = QCursor::pos();
QDropEvent drop_event { mouse_pos, Qt::MoveAction, mime_data, Qt::NoButton, Qt::NoModifier };
QApplication::sendEvent(screen, &drop_event);
}
protected:
void keyPressEvent(QKeyEvent* e) override {
switch (e->key()) {
case Qt::Key_M:
move_file();
break;
default:
QMainWindow::keyPressEvent(e);
}
}
void mousePressEvent(QMouseEvent*) override {
auto* mime = new QMimeData;
mime->setUrls(QList<QUrl> { } << m_file);
auto* drag = new QDrag { this };
drag->setMimeData(mime);
drag->exec();
}
public:
DragDropTester(const QString& path) : QMainWindow { } {
m_file = QUrl::fromLocalFile(path);
setFixedSize(400, 400);
show();
}
};
To copy to clipboard, switch view to plain text mode
The drag & drop with mouse using QDrag works, but the key version does not.
Unfortunately it looks like QDrag is implemented to always listen for mouse release event to determine when to finalize the drop, instead of providing a ".drop()" function or similar ..
I looked around in the doc and I think I need to construct and handle my own QDropEvent, which I tried to do in the above code, but it does not work.
In particular I am unsure about several points:
- The QDropEvent::QDropEvent(.. doc says "Constructs a drop event ... at the point specified by pos in the destination widget's coordinate system". Is the "destination" widget the "receiver" that I pass to my QDropEvent? I not, what would the correct pos be to provide the global mouse position on the OS desktop?
- I am not really sure if sendEvent does what I want ?
- The QCoreApplication::sendEvent(.. doc says "Sends event event directly to receiver receiver, ...". receiver is a QObject* .. I don't know if passing QScreen* to this makes sense? I assume the receiver must implement dropEvent(), but QScreen is not a widget ... This is probably wrong, but I don't know what else to pass as receiver, what would the correct receiver be in my case?
Or maybe there is completely different way and trying to construct / handle QDropEvent is wrong? Help appreciated!
Edit: A second idea: I could simulate the mouse events by sending them from the key events, but I am also stuck trying to get this to work:
// in keyPressEvent ...
case Qt::Key_M:
if (!e->isAutoRepeat()) {
Qt::LeftButton, Qt::NoButton, Qt::NoModifier };
}
break;
// in keyPressEvent ...
case Qt::Key_M:
if (!e->isAutoRepeat()) {
QMouseEvent mouse_event { QEvent::MouseButtonPress, mapFromGlobal(QCursor::pos()),
Qt::LeftButton, Qt::NoButton, Qt::NoModifier };
QApplication::sendEvent(this, &mouse_event);
}
break;
To copy to clipboard, switch view to plain text mode
This triggers the mouse event, but the QDrag does not show up (i.e. nothing happens and the icon that I get when I instead click the mouse does not show). Maybe because the mouse button needs to be held down, but I don't see any event setting for this
Bookmarks