Unsolved QML: How to drag & drop files to application's main window?
-
Here is a working example that shows I can attach files with a FileDialog, but I cannot do the same via Drag & Drop. I'm running this QML app on desktop Linux (KDE).
When a file is drug and dropped onto the main window, I need to get the full file path and filename as text.
The code I have here actually functions on Mac, but I don't think I have done the correct implementation. Now that I have studied more examples while troubleshooting this, it appears that the method I used to implement drag and drop is intended for text selections. Indeed, my app will accept text selections dropped onto it. But it does not accept files (at least on Linux).
When I drop a file onto the app window, the onDropped method is called. In there I do a console.log and drop.text is empty and drag.source is null.
How is dragging and dropping of files (from Dolphin file manager) to the QML application window supposed to be implemented?
Below are my python and qml files:
QML:
import QtQuick.Window 2.2 import QtQuick 2.2 import QtQuick.Controls 1.3 import QtQuick.Layouts 1.3 import QtQuick.Dialogs 1.0 ApplicationWindow { id: rootId visible: true title: "Drag Drop MRE" property int margin: 16 minimumWidth: 600 minimumHeight: 480 FileDialog { id: fileDialog title: "Choose File Attachment" folder: shortcuts.home onAccepted: { attachments.text += fileDialog.fileUrls + '\n' console.log("added attachment: " + fileDialog.fileUrls) } } DropArea{ id: drop enabled: true anchors.fill: parent anchors.margins: margin Rectangle { anchors.fill: parent color: "green" visible: parent.containsDrag } onEntered: console.log("entered DropArea") onDropped:{ attachments.text += drop.text + '\n' console.log("added attachment: " + drop.text) console.log("drag.source: " + drag.source) } GridLayout { id: mainLayout anchors.fill: parent anchors.margins: margin Label { text: "Drag Drop MRE" font.pixelSize: 16 Layout.row: 1 Layout.column: 1 } GroupBox { Layout.row: 2 Layout.column: 1 id: gridBox Layout.fillWidth: true GridLayout { id: gridLayout rows: 1 flow: GridLayout.TopToBottom anchors.fill: parent Label { text: "Attached files" } TextArea { id: attachments Layout.fillWidth: true implicitHeight: 300 } } } GroupBox { Layout.row: 3 Layout.column: 1 id: rowBox Layout.fillWidth: true Row { anchors.right: parent.right id: rowLayout Button { id: attach_button text: "Attach" onClicked: fileDialog.open(); } Button { id: save_button text: "Save" onClicked: backend.dropaccept(attachments.text) } Button { id: exit_button text: "Exit" onClicked: Qt.quit() } } } }} // Grid Layout & Drop Area }
python:
import sys from PyQt5.QtWidgets import QApplication from PyQt5.QtCore import Qt, QCoreApplication, QObject, pyqtSlot from PyQt5.QtQml import QQmlApplicationEngine import os import re import getpass # from shutil import copyfile class Backend(QObject): def cleanup(self, string): return re.sub(r'\W+', '_', string) @pyqtSlot(str) def dropaccept(self, files): basepath = '/home/' + getpass.getuser() for file in files.split('\n'): if file.replace(' ', '') == '': continue try: file = file.replace('file://', '') path_to_save = basepath + "/" + os.path.basename(file) print("save path: " + path_to_save) except Exception: print("bad file path") if __name__ == '__main__': backend = Backend() QApplication.setAttribute(Qt.AA_EnableHighDpiScaling) QCoreApplication.setAttribute(Qt.AA_UseHighDpiPixmaps) app = QApplication(sys.argv) engine = QQmlApplicationEngine('dragdropmre.qml') engine.rootContext().setContextProperty("backend", backend) sys.exit(app.exec_())
-
The example below works fine both for text and files (Linux Mint with Nemo as file manager):
DropArea { anchors.fill: parent onDropped: { console.log(drop.text); } }