Making a QML Element "droppable"



  • Hi guys,

    First post - hope you can help!

    Basically I would like to make one of my QML elements be able to receive files from a File Manager/Desktop by dragging them into my application. I'm sure I need to create the QML element in Qt first so I can override dragEnterEvent and dropEvent, and although dragEnterEvent seems to work OK, it appears dropEvent never seems to run.

    From my code below, the debug console reports "dragEnterEvent entered" and "Proposed Action accepted" whenever I drag into my QML element, however displays the Windows unavailable cursor. The console does NOT display "dropEvent entered" at any point.

    Hopefully I'm just missing something stupid, but can't for the life of me work it out! Am I going the right way about things here? And is what I am trying to acheive possible? It works fine with regular QWidgets but not when using QML elements!

    Thanks in advance.

    @//main.cpp
    #include <QtGui/QApplication>
    #include "qmlapplicationviewer.h"
    #include <QtDeclarative/QDeclarativeContext>
    #include "mainwindow.h"

    int main(int argc, char *argv[])
    {
    QApplication app(argc, argv);

    MainWindow mw;
    
    mw.setWindowFlags(Qt::FramelessWindowHint) ;
    mw.setAttribute(Qt::WA_TranslucentBackground);
    mw.setStyleSheet("background:transparent");
    
    mw.show();
    
    return app.exec();
    

    }@

    @//mainwindow.h
    #ifndef MAINWINDOW_H
    #define MAINWINDOW_H

    #include <QMainWindow>
    #include <QtDeclarative>
    #include "testwidget.h"

    class MainWindow : public QDeclarativeView
    {
    Q_OBJECT
    public:
    QPoint mpos;
    bool m_canMoveWindow;

    explicit MainWindow(QWidget *parent = 0);
    void mousePressEvent(QMouseEvent *event);
    void mouseMoveEvent(QMouseEvent *event);
    void mouseReleaseEvent(QMouseEvent *event);
    

    signals:

    public slots:

    };

    #endif // MAINWINDOW_H@

    @//mainwindow.cpp
    #include "mainwindow.h"

    MainWindow::MainWindow(QWidget *parent) :
    QDeclarativeView(parent)
    {
    rootContext()->setContextProperty("mainwnd",this);
    setResizeMode(QDeclarativeView::SizeRootObjectToView);
    setSource(QUrl("qml/untitled/main.qml"));

    TestWidget *tw = new TestWidget(this);
    tw->show();
    

    }

    void MainWindow::mousePressEvent(QMouseEvent *event)
    {
    if(event->button() != Qt::LeftButton)
    return;

    mpos = event->pos();
    
    if(mpos.y() <= 20)
        m_canMoveWindow = true;
    
    QDeclarativeView::mousePressEvent(event);
    

    }

    void MainWindow::mouseMoveEvent(QMouseEvent *event)
    {
    QDeclarativeView::mouseMoveEvent(event);

    if(!m_canMoveWindow)
        return;
    
    move(pos() + event->pos() - mpos);
    

    }

    void MainWindow::mouseReleaseEvent(QMouseEvent *event)
    {
    m_canMoveWindow = false;

    QDeclarativeView::mouseReleaseEvent(event);
    

    }@

    @//testwidget.h
    #ifndef TESTWIDGET_H
    #define TESTWIDGET_H

    #include <QWidget>
    #include <QtDeclarative>

    class TestWidget : public QDeclarativeView
    {
    Q_OBJECT
    public:
    explicit TestWidget(QWidget *parent = 0);
    void dragEnterEvent(QDragEnterEvent *event);
    void dropEvent(QDropEvent *event);

    signals:

    public slots:

    };

    #endif // TESTWIDGET_H@

    @//testwidget.cpp
    #include "testwidget.h"

    TestWidget::TestWidget(QWidget *parent) :
    QDeclarativeView(parent)
    {
    setFixedSize(100, 62);
    setGeometry(20, 40, 100, 62);
    rootContext()->setContextProperty("dropbox",this);
    setResizeMode(QDeclarativeView::SizeRootObjectToView);
    setSource(QUrl("qml/untitled/DropBox.qml"));

    setAcceptDrops(true);
    

    }

    void TestWidget::dragEnterEvent(QDragEnterEvent *event)
    {
    qDebug() << "dragEnterEvent entered";

    if(event->mimeData()->hasUrls())
    {
        event->acceptProposedAction();
        qDebug() << "Proposed Action accepted";
    }
    

    }

    void TestWidget::dropEvent(QDropEvent *event)
    {
    qDebug() << "dropEvent entered";

    QList<QUrl> droppedUrls = event->mimeData()->urls();
    
    for(int i = 0; i < droppedUrls.size(); i++) {
        QString localPath = droppedUrls[i].toLocalFile&#40;&#41;;
        QFileInfo fileInfo(localPath);
        qDebug() << fileInfo.absoluteFilePath();
    }
    
    event->acceptProposedAction();
    

    }@

    @//main.qml
    // import QtQuick 1.0 // to target S60 5th Edition or Maemo 5
    import QtQuick 1.1

    Rectangle {
    width: 360; height: 360
    color: "white"
    border.width: 2; border.color: "black"

    Rectangle {
        width: parent.width; height: 20
        color: "black"
    
        Text {
            anchors.horizontalCenter: parent.horizontalCenter
            anchors.verticalCenter: parent.verticalCenter
            color: "white"
            text: "My App"
        }
    }
    
    /*DropBox {
        anchors.horizontalCenter: parent.horizontalCenter
        anchors.verticalCenter: parent.verticalCenter
    }*/
    

    }@

    @//DropBox.qml
    // import QtQuick 1.0 // to target S60 5th Edition or Maemo 5
    import QtQuick 1.1

    Rectangle {
    width: 100; height: 62
    border.color: "black"; border.width: 1

    Text {
        text: "Drop Box"
        anchors.horizontalCenter: parent.horizontalCenter
        anchors.verticalCenter: parent.verticalCenter
    }
    

    }@



  • Thanks for anyone who took the time to read this, however I have figured it out - finally!

    I guess QDeclarativeView cannot be dragged onto, so I changed my TestWidget class to inherit QWidget instead, and placed the QDeclarative object in the QWidget. In the dragEnterEvent for the QWidget, I made the QDeclarativeView transparent to mouse events (so I was always dragging onto the QWidget instead of the QDeclarativeView). I then removed this attribute in the dragLeaveEvent and dropEvent.

    This did the trick! New code for TestWidget below:

    @//testwidget.cpp

    #include "testwidget.h"

    TestWidget::TestWidget(QWidget *parent) :
    QWidget(parent)
    {
    qc = new QDeclarativeView(this);
    qc->setFixedSize(100, 62);
    qc->setGeometry(20, 60, 100, 62);
    qc->rootContext()->setContextProperty("dropbox",this);
    qc->setResizeMode(QDeclarativeView::SizeRootObjectToView);
    qc->setSource(QUrl("qml/untitled/DropBox.qml"));

    this->setAcceptDrops(true);
    

    }

    void TestWidget::dragEnterEvent(QDragEnterEvent *event)
    {
    qc->setAttribute(Qt::WA_TransparentForMouseEvents, true);

    qDebug() << "dragEnterEvent entered";
    
    if(event->mimeData()->hasUrls())
    {
        event->acceptProposedAction();
        qDebug() << "Proposed Action accepted";
    }
    

    }

    void TestWidget::dragLeaveEvent(QDragLeaveEvent *)
    {
    qc->setAttribute(Qt::WA_TransparentForMouseEvents, false);
    }

    void TestWidget::dropEvent(QDropEvent *event)
    {
    qDebug() << "dropEvent entered";

    QList<QUrl> droppedUrls = event->mimeData()->urls();
    
    for(int i = 0; i < droppedUrls.size(); i++) {
        QString localPath = droppedUrls[i].toLocalFile&#40;&#41;;
        QFileInfo fileInfo(localPath&#41;;
        qDebug() << fileInfo.absoluteFilePath();
    }
    
    event->acceptProposedAction();
    
    qc->setAttribute(Qt::WA_TransparentForMouseEvents, false);
    

    }@

    @//testwidget.h

    #ifndef TESTWIDGET_H
    #define TESTWIDGET_H

    #include <QWidget>
    #include <QtDeclarative>

    class TestWidget : public QWidget
    {
    Q_OBJECT
    public:
    QDeclarativeView *qc;

    explicit TestWidget(QWidget *parent = 0);
    void dragEnterEvent(QDragEnterEvent *event);
    void dragLeaveEvent(QDragLeaveEvent *event);
    void dropEvent(QDropEvent *event);
    

    signals:

    public slots:

    };

    #endif // TESTWIDGET_H@


  • Moderators

    Oh good, I was about to reply now I got back from classes.

    Nice solution, thanks for sharing.


Log in to reply
 

Looks like your connection to Qt Forum was lost, please wait while we try to reconnect.