How to obtain the full path of a file (or multiple files) after drag/drop it from a folder to a QListWidget

Viewed 40

I have a small problem: How do I obtain the full path of a file (or multiple files) after I drag/drop it on a QListWidget?

I prepared a small verifiable example where I implemented the drag and drop function. The ui is composed only by 1 QListWidget and a QTableView (not used yet).

Below the wrong result after I drag and drop 2 files from a /home folder

enter image description here

Below the desired result I am looking for after I drag and drop the files from a folder:

enter image description here

Yes, you already guessed it right. The reason is that I would want the user to be able to visualize all the time where those files came from after dragging/dropping from different folders.

Below the Minimal verifiable example. You can copy/past on your machine and it will work no problem:

main.cpp

#include "mainwindow.h"
#include <QApplication>

int main(int argc, char *argv[])
{
    QApplication a(argc, argv);
    MainWindow w;
    w.show();
    return a.exec();
}

mainwindow.h

#define MAINWINDOW_H
#include <QMainWindow>

QT_BEGIN_NAMESPACE
namespace Ui { class MainWindow; }
QT_END_NAMESPACE

class MainWindow : public QMainWindow
{
    Q_OBJECT

public:
    MainWindow(QWidget *parent = nullptr);
    ~MainWindow();

protected:
    void dragEnterEvent(QDragEnterEvent *event);
    void dragLeaveEvent(QDragLeaveEvent *event);
    void dragMoveEvent(QDragMoveEvent *event);
    void dropEvent(QDropEvent *event);

private:
    Ui::MainWindow *ui;
};
#endif // MAINWINDOW_H

mainwindow.cpp

#include "mainwindow.h"
#include "ui_mainwindow.h"

#include <QDragEnterEvent>
#include <QDragLeaveEvent>
#include <QDragMoveEvent>
#include <QDropEvent>
#include <QMimeData>

MainWindow::MainWindow(QWidget *parent)
    : QMainWindow(parent)
    , ui(new Ui::MainWindow)
{
    ui->setupUi(this);
    setAcceptDrops(true);
}

MainWindow::~MainWindow()
{
    delete ui;
}

void MainWindow::dragEnterEvent(QDragEnterEvent *event)
{
    event->accept();
}
void MainWindow::dragLeaveEvent(QDragLeaveEvent *event)
{
    event->accept();
}
void MainWindow::dragMoveEvent(QDragMoveEvent *event)
{
    event->accept();
}
void MainWindow::dropEvent(QDropEvent *event)
{
    QString name;
    QList<QUrl> urls;
    QList<QUrl>::Iterator i;
    urls = event->mimeData()->urls();
    for(i = urls.begin(); i != urls.end(); ++i) {
        name = i->fileName();
        ui->listWidget->addItem(name);
    }
}

Below is what I have done so far:

In an attempt to try to solve it by myself I consulted this source but it mainly describe how to promote the widget, which is not my case. Also I read this one which seems to be good but still does not work. Finally I studied this but is not exactly what I am looking for as it deals with QGraphicsView.

Finally I tried to implement the dropEvent(QDropEvent *event) a little bit differently as explained below, it is close but still does not work as I expect because the drop event will leave the files in the same row but this is wrong. Close, but wrong:

void MainWindow::dropEvent(QDropEvent *event)
{
    const QMimeData *mimeData = event->mimeData();
    QList<QUrl> urlList = mimeData->urls();
    QString text;

    for (int i = 0; i < urlList.size(); ++i)
        text += urlList.at(i).path() + QLatin1Char('\n');
    ui->listWidget->addItem(text);
}

As you can see this is also wrong because as soon as I drag/drop multiple files, they are seen as one single row in the QListWidget as highlighted in the row:

enter image description here

Thanks for any pointers to the solution.

1 Answers

As pointed out by @Fareanor, in order to get the path of a file (or multiple files) after dragging and dropping them into a QListWidget simply use QUrl::path() and you are good to go. Below the answer to the question:

void MainWindow::dropEvent(QDropEvent *event)
{
    QString name;
    QList<QUrl> urls;
    QList<QUrl>::Iterator i;
    urls = event->mimeData()->urls();
    for(i = urls.begin(); i != urls.end(); ++i) {
        name = i->path(); // <-- Correct way to get the full path
        ui->listWidget->addItem(name);
    }
}
Related