Qtドラッグ&ドロップアシスタントクラス——Qtコントロールのドラッグ&ドロッププログラムの作成を簡略化

3572 ワード

Qtプログラムでは、ドラッグ&ドロップ機能がよく使用されるため、ネット上の多くの例は、このクラスの2つの虚関数を直接書き換えるものです.
protected:
    virtual void dragEnterEvent(QDragEnterEvent *event) override;
    virtual void dropEvent(QDropEvent *event) override;

しかしながら、各コントロールは、コードの簡潔性を低下させ、書き換えであるため、上記2つの虚関数をヘッダファイルに暴露せざるを得ない.
だから、クラスを書いて、イベントフィルタでコードを簡略化できるかどうか、ずっと考えていました.
答えはいいです.
あまり話さないで、直接コードをつけます.
dragdrophelper.h:
#ifndef DRAGDROPHELPER_H
#define DRAGDROPHELPER_H

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

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

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

signals:
    void resourceDropped(const QList &urls);

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

#endif // DRAGDROPHELPER_H

dragdrophelper.cpp:
#include "dragdrophelper.h"

/*!
 * \brief     ,            
 * \details             dragEnterEvent() dropEvent(),
 *                 resourceDropped()             
 * \param beneficiary        
 * \param types           ,           '|'     
 */
DragDropHelper::DragDropHelper(QWidget *beneficiary, AllowedTypes types) : QObject(beneficiary)
{
    this->types = types;
    beneficiary->setAcceptDrops(true);
    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(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(event);
        if ( e )
            emit resourceDropped( e->mimeData()->urls() );
    }
    return QObject::eventFilter(watched, event);
}

bool DragDropHelper::allResourceAllowed(const QList &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;
}

使用:(ドラッグアンドドロップの場合、処理を実行するオブジェクトはwidget、処理するスロット関数はloadFiles()と仮定)
    DragDropHelper *dragDropHelper = new DragDropHelper(widget, DragDropHelper::File);
    connect(dragDropHelper, SIGNAL(resourceDropped(QList)), widget, SLOT(loadFiles(QList)));

これにより,文章の最初に言及した2つの虚関数を書き換えることがなくなり,スロット関数を1つ書くだけでよい.
さらに、イベントフィルタは動的にインストール/アンインストールでき、実行中に何らかの動作に応答するかどうかを選択できます.