Skip to content
  • Categories
  • Recent
  • Tags
  • Popular
  • Users
  • Groups
  • Search
  • Get Qt Extensions
  • Unsolved
Collapse
Brand Logo
  1. Home
  2. Qt Development
  3. General and Desktop
  4. Drag and Drop Implementation
QtWS25 Last Chance

Drag and Drop Implementation

Scheduled Pinned Locked Moved Unsolved General and Desktop
drag and dropqlabelicons
9 Posts 3 Posters 2.7k Views
  • Oldest to Newest
  • Newest to Oldest
  • Most Votes
Reply
  • Reply as topic
Log in to reply
This topic has been deleted. Only users with topic management privileges can see it.
  • W Offline
    W Offline
    Wiki_Wut
    wrote on 19 Apr 2022, 16:08 last edited by
    #1

    Hello everyone, I'm having a bit of an issue with trying to understand Drag and Drop within Qt. I'm a beginner with both coding and Qt, but loving Qt so far! Ok, here's my situation: I've looked up the documentation for Drag and Drop and checked out the examples, specifically the Draggable Icons example (with the boat, house, and car icons). I'm trying to modify it to fit my specific situation, but I'm sure I'm missing several things, so here it goes.

    Here's a screenshot of the basic setup I have made in Qt Creator:
    Left Side: Large QLabel; Right Side: Group Box with Icons to be set as draggable.

    There is a group box on the right with some icons in it, I want to make those icons draggable. The large gray box on the left is a QLabel in which a user can select an image to load into it. I want that large QLabel to be where the user can drop any of the icons from the right group box and arrange them as they desire (and drop as many of them as they would like as well). The draggable icons example was perfect for what I wanted, but I cannot get it to work. I'm to understand that I make the QLabels with the icons draggable by subclassing them (is that the same as "Promoting" them?), so I made a class called draggable and then I made another class called DropArea. However, when I "Promote" the icons to Draggable and the large QLabel to Drop Area, nothing happens when I build and run. Again, I know I'm missing several things. What am I missing and/or doing wrong? Here's my code:

    Draggable.h

    #ifndef DRAGGABLE_H
    #define DRAGGABLE_H
    
    #include <QLabel>
    
    class Draggable : public QLabel
    {
    public:
        explicit Draggable(QWidget *parent = nullptr);
    
    protected:
        void dragMoveEvent(QDragMoveEvent *event) override;
        void mousePressEvent(QMouseEvent *event) override;
    };
    
    #endif // DRAGGABLE_H
    

    DropArea.h

    #ifndef DROPAREA_H
    #define DROPAREA_H
    
    #include <QLabel>
    
    class DropArea : public QLabel
    {
    public:
        explicit DragWidget(QWidget *parent = nullptr);
    
    protected:
        void dragEnterEvent(QDragEnterEvent *event) override;
        void dragMoveEvent(QDragMoveEvent *event) override;
        void dropEvent(QDropEvent *event) override;
        void mousePressEvent(QMouseEvent *event) override;
    };
    
    #endif // DROPAREA_H
    

    And here are my source files:

    Draggable.cpp

    #include <QtWidgets>
    #include "draggable.h"
    
    Draggable::Draggable(QWidget *parent) : QLabel(parent)
    {
    }
    
    void Draggable::dragMoveEvent(QDragMoveEvent *event)
    {
        if (event->mimeData()->hasFormat("application/icondata"))
        {
            if (event->source() == this)
    	{
                event->setDropAction(Qt::MoveAction);
                event->accept();
            }
    	else
    	{
                event->acceptProposedAction();
            }
        }
        else
        {
            event->ignore();
        }
    }
    
    void Draggable::mousePressEvent(QMouseEvent *event)
    {
        QLabel *child = static_cast<QLabel*>(childAt(event->pos()));
        if (!child)
            return;
    
        QPixmap pixmap = child->pixmap(Qt::ReturnByValue);
    
        QByteArray itemData;
        QDataStream dataStream(&itemData, QIODevice::WriteOnly);
        dataStream << pixmap << QPoint(event->pos() - child->pos());
    
        QMimeData *mimeData = new QMimeData;
        mimeData->setData("application/icondata", itemData);
    
        QDrag *drag = new QDrag(this);
        drag->setMimeData(mimeData);
        drag->setPixmap(pixmap);
        drag->setHotSpot(event->pos() - child->pos());
    
        QPixmap tempPixmap = pixmap;
        QPainter painter;
        painter.begin(&tempPixmap);
        painter.fillRect(pixmap.rect(), QColor(127, 127, 127, 127));
        painter.end();
    
        child->setPixmap(tempPixmap);
    
        if (drag->exec(Qt::CopyAction | Qt::MoveAction, Qt::CopyAction) == Qt::MoveAction)
        {
            child->close();
        }
        else
        {
            child->show();
            child->setPixmap(pixmap);
        }
    }
    

    DropArea.cpp

    #include <QtWidgets>
    #include "draggable.h"
    
    Draggable::Draggable(QWidget *parent) : QLabel(parent)
    {
    }
    
    void Draggable::dragEnterEvent(QDragEnterEvent *event)
    {
        if (event->mimeData()->hasFormat("application/icondata"))
        {
            if (event->source() == this)
    	{
                event->setDropAction(Qt::MoveAction);
                event->accept();
            }
    	else
    	{
                event->acceptProposedAction();
            }
        }
        else
        {
            event->ignore();
        }
    }
    
    void Draggable::dragMoveEvent(QDragMoveEvent *event)
    {
        if (event->mimeData()->hasFormat("application/icondata"))
        {
            if (event->source() == this)
    	{
                event->setDropAction(Qt::MoveAction);
                event->accept();
            }
    	else
    	{
                event->acceptProposedAction();
            }
        }
        else
        {
            event->ignore();
        }
    }
    
    void Draggable::dropEvent(QDropEvent *event)
    {
        if (event->mimeData()->hasFormat("application/icondata"))
        {
            QByteArray itemData = event->mimeData()->data("application/icondata");
            QDataStream dataStream(&itemData, QIODevice::ReadOnly);
    
            QPixmap pixmap;
            QPoint offset;
            dataStream >> pixmap >> offset;
    
            QLabel *newIcon = new QLabel(this);
            newIcon->setPixmap(pixmap);
            newIcon->move(event->pos() - offset);
            newIcon->show();
            newIcon->setAttribute(Qt::WA_DeleteOnClose);
    
            if (event->source() == this)
    	{
                event->setDropAction(Qt::MoveAction);
                event->accept();
            }
    	else
    	{
                event->acceptProposedAction();
            }
        }
        else
        {
            event->ignore();
        }
    }
    
    void Draggable::mousePressEvent(QMouseEvent *event)
    {
        QLabel *child = static_cast<QLabel*>(childAt(event->pos()));
        if (!child)
            return;
    
        QPixmap pixmap = child->pixmap(Qt::ReturnByValue);
    
        QByteArray itemData;
        QDataStream dataStream(&itemData, QIODevice::WriteOnly);
        dataStream << pixmap << QPoint(event->pos() - child->pos());
    
        QMimeData *mimeData = new QMimeData;
        mimeData->setData("application/icondata", itemData);
    
        QDrag *drag = new QDrag(this);
        drag->setMimeData(mimeData);
        drag->setPixmap(pixmap);
        drag->setHotSpot(event->pos() - child->pos());
    
        QPixmap tempPixmap = pixmap;
        QPainter painter;
        painter.begin(&tempPixmap);
        painter.fillRect(pixmap.rect(), QColor(127, 127, 127, 127));
        painter.end();
    
        child->setPixmap(tempPixmap);
    
        if (drag->exec(Qt::CopyAction | Qt::MoveAction, Qt::CopyAction) == Qt::MoveAction)
        {
            child->close();
        }
        else
        {
            child->show();
            child->setPixmap(pixmap);
        }
    }
    

    As you can see, I've taken much of the code from the draggable icons example and tried to implement it into my program. Again, please forgive me if I am doing something dumb or what an experienced coder would consider stupid, I'm still trying to learn. I left my constructor blank for the draggable class because I'm thinking that the QLabels with pixmap icons are already created in Qt Creator and I just want the drag and drop functionality from the other functions of the class. Is that wrong? If so, what should I have in my constructor? And what else do I need to correct/change in my code?

    Thank you for taking a look at my issue, I really appreciate your time and help with this.

    1 Reply Last reply
    0
    • S Offline
      S Offline
      SGaist
      Lifetime Qt Champion
      wrote on 19 Apr 2022, 19:16 last edited by
      #2

      Hi and welcome to devnet,

      From the looks of it, you split the functionality of the original widget the wrong way. I might be wrong but I think the Drag And Drop Puzzle example might be closer to what you want to do (i.e. one drag source and a different drop target).

      As for the Promotion feature of designer it's not the same as inheritance. You have to subclass one of the base widget in order to use it though.

      Interested in AI ? www.idiap.ch
      Please read the Qt Code of Conduct - https://forum.qt.io/topic/113070/qt-code-of-conduct

      1 Reply Last reply
      0
      • W Offline
        W Offline
        Wiki_Wut
        wrote on 19 Apr 2022, 19:52 last edited by
        #3

        Hi SGaist,
        Thank you for your welcome and reply.

        Ok, I will look more closely at the Puzzle example. Thank you for pointing that out. In terms of subclassing, what does that mean? How would I subclass a base widget? I think I've been misunderstanding the term when I see other coders use it.

        Thanks again, I really appreciate your help :)

        1 Reply Last reply
        0
        • S Offline
          S Offline
          SGaist
          Lifetime Qt Champion
          wrote on 19 Apr 2022, 20:11 last edited by
          #4

          Subclassing is the action of creating a new class based on an existing one. For example, QLabel inherits from QWidget.

          Interested in AI ? www.idiap.ch
          Please read the Qt Code of Conduct - https://forum.qt.io/topic/113070/qt-code-of-conduct

          1 Reply Last reply
          0
          • W Offline
            W Offline
            Wiki_Wut
            wrote on 19 Apr 2022, 20:32 last edited by
            #5

            Oh ok, so for the following line:

            class MyClass : public QLabel
            {...}

            this would mean that MyClass is inheriting from QLabel? Am I understanding that correctly?

            J 1 Reply Last reply 20 Apr 2022, 06:22
            0
            • W Wiki_Wut
              19 Apr 2022, 20:32

              Oh ok, so for the following line:

              class MyClass : public QLabel
              {...}

              this would mean that MyClass is inheriting from QLabel? Am I understanding that correctly?

              J Offline
              J Offline
              jsulm
              Lifetime Qt Champion
              wrote on 20 Apr 2022, 06:22 last edited by
              #6

              @Wiki_Wut said in Drag and Drop Implementation:

              this would mean that MyClass is inheriting from QLabel?

              yes

              https://forum.qt.io/topic/113070/qt-code-of-conduct

              1 Reply Last reply
              0
              • W Offline
                W Offline
                Wiki_Wut
                wrote on 21 Apr 2022, 19:14 last edited by
                #7

                Thank you for your help. Unfortunately, I still cannot figure it out. I can't get that darn label to move, let alone be dragged and dropped. There's much about the examples I do not understand. Does anyone know if there is a good tutorial/article/source that thoroughly explains drag and drop functionality. When I say thoroughly, I mean going through the code and explaining line by line how it works since I'm a beginner with both Qt and coding? If not, that's ok, I still very much appreciate your time and help.

                1 Reply Last reply
                0
                • S Offline
                  S Offline
                  SGaist
                  Lifetime Qt Champion
                  wrote on 21 Apr 2022, 19:30 last edited by
                  #8

                  You should check the VoidRealms YouTube channel. It has a very extensive set of Qt related videos which may interest you.

                  Interested in AI ? www.idiap.ch
                  Please read the Qt Code of Conduct - https://forum.qt.io/topic/113070/qt-code-of-conduct

                  1 Reply Last reply
                  0
                  • W Offline
                    W Offline
                    Wiki_Wut
                    wrote on 21 Apr 2022, 19:30 last edited by
                    #9

                    Awesome, I will check that out, thank you very much!

                    1 Reply Last reply
                    0

                    9/9

                    21 Apr 2022, 19:30

                    • Login

                    • Login or register to search.
                    9 out of 9
                    • First post
                      9/9
                      Last post
                    0
                    • Categories
                    • Recent
                    • Tags
                    • Popular
                    • Users
                    • Groups
                    • Search
                    • Get Qt Extensions
                    • Unsolved