Qt Drag-and-Drop Assistant Class-Simplified Drag-and-Drop Programming for Qt Controls

Posted by bmcewan on Sat, 05 Oct 2019 03:19:23 +0200

Because drag-and-drop functions are often used in Qt programs, many examples on the Internet directly rewrite two virtual functions of this kind:

protected:
    virtual void dragEnterEvent(QDragEnterEvent *event) override;
    virtual void dropEvent(QDropEvent *event) override;

However, each control writes to it in such a way that the code is less concise, and because it is rewritten, the two virtual functions mentioned above have to be exposed in the header file.

So, I've been thinking, can I write a class to simplify the code through event filters?

The answer is yes.

Not much to say, go directly to the code:

dragdrophelper.h:

#ifndef DRAGDROPHELPER_H
#define DRAGDROPHELPER_H

#include <QtGui>
#if QT_VERSION >= QT_VERSION_CHECK(5,0,0)
#include <QtWidgets>
#endif

class DragDropHelper : public QObject
{
    Q_OBJECT
public:
    enum  AllowedType { None = 0, File = 1, Directory = 2 };
    Q_DECLARE_FLAGS(AllowedTypes, AllowedType)

    explicit DragDropHelper(QObject *beneficiary, AllowedTypes types = File);
    void setAllowedTypes(AllowedTypes types);

signals:
    void resourceDropped(const QList<QUrl> &urls);

private:
    AllowedTypes types;
    virtual bool eventFilter(QObject *watched, QEvent *event) override;
    bool allResourceAllowed(const QList<QUrl> &urls);
};
Q_DECLARE_OPERATORS_FOR_FLAGS(DragDropHelper::AllowedTypes)

#endif // DRAGDROPHELPER_H

dragdrophelper.cpp:

#include "dragdrophelper.h"

/*!
 * \brief Drag assistants can simplify drag-and-drop implementation of a class
 * \details The class of the assisted object does not need to override dragEnterEvent() and dropEvent().
 *              Simply connect the resourceDropped() signal to the slot function for resource processing
 * \param beneficiary Objects of assistance
 * \param types Types of objects allowed to be dragged in, different types of objects can be combined with or with the operator'|'
 */
DragDropHelper::DragDropHelper(QObject *beneficiary, AllowedTypes types) : QObject(beneficiary)
{
    this->types = types;
    beneficiary->installEventFilter(this);
}

void DragDropHelper::setAllowedTypes(AllowedTypes types)
{
    this->types = types;
}

bool DragDropHelper::eventFilter(QObject *watched, QEvent *event)
{
    if ( event->type() == QEvent::DragEnter ) {
        QDragEnterEvent *e = dynamic_cast<QDragEnterEvent *>(event);
        if ( !e || !e->mimeData()->hasUrls() )
            return QObject::eventFilter(watched, event);
        if ( allResourceAllowed( e->mimeData()->urls() ) ) {
            e->acceptProposedAction();
            return true;
        }
    } else if ( event->type() == QEvent::Drop ) {
        QDropEvent *e = dynamic_cast<QDropEvent *>(event);
        if ( e )
            emit resourceDropped( e->mimeData()->urls() );
    }
    return QObject::eventFilter(watched, event);
}

bool DragDropHelper::allResourceAllowed(const QList<QUrl> &urls)
{
    if ( urls.isEmpty() )
        return false;
    if ( types.testFlag(File) && types.testFlag(Directory) )
        return true;
    if ( types.testFlag(File) )
        foreach (QUrl url, urls)
            if ( !QFileInfo(url.toLocalFile()).isFile() )
                return false;
    if ( types.testFlag(Directory) )
        foreach (QUrl url, urls)
            if ( !QFileInfo(url.toLocalFile()).isDir() )
                return false;
    return true;
}

Use: (Assuming that when dragging and dropping, the object of processing is widget and the slot function of processing is loadFiles()).

    DragDropHelper *dragDropHelper = new DragDropHelper(this, DragDropHelper::Directory);
    connect(dragDropHelper, SIGNAL(resourceDropped(QList<QUrl>)), widget, SLOT(loadFiles(QList<QUrl>)));

In this way, the two virtual functions mentioned at the beginning of the article are not rewritten, and only one slot function is needed.

In addition, the event filter can also dynamically install/uninstall processing functions, making the program more flexible.

 

Topics: Qt less