c++qtdrag-and-dropdraggableqlistview

Why drag&drop does not called dropEvent?


I guess no one knows about it. I've been asking the same question for 2 days, and no one answers.

I find a toDoList project about drag&drop. And I wonder Can I get the item that dragging or dropped. I'm reading the documentation for 2 days. I implement the methods.

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

There are 2 listviews and toolbar. I add add and remove to the toolbar.
I can drag or drop but, I can't get text of the the items dragging. This is the main code. And I really wonder, we override the methods right. But we do not connect the methods to something. How does the method works ?

todolist::todolist(QWidget *parent)
    : QMainWindow(parent)
    , ui(new Ui::todolist)
{
    QWidget* pWidget = new QWidget(this);
        pWidget->setStyleSheet("background-color: #ECF0F1");
        setCentralWidget(pWidget);

        QVBoxLayout* pMainLayout = new QVBoxLayout();
        pWidget->setLayout(pMainLayout);

        QLabel* pwTitle = new QLabel("To Do List", this);
        pMainLayout->addWidget(pwTitle);
        pwTitle->setAlignment(Qt::AlignCenter);
        pwTitle->setStyleSheet("font-size: 30pt; margin: 10%;");

        QHBoxLayout* pHLayoutLabels = new QHBoxLayout();
        pMainLayout->addLayout(pHLayoutLabels);

        QLabel* plblPending = new QLabel("Pending", this);
        plblPending->setStyleSheet("font-size: 15pt;");
        pHLayoutLabels->addWidget(plblPending);

        QLabel* plblCompleted = new QLabel("Completed", this);
        plblCompleted->setStyleSheet("font-size: 15pt;");
        pHLayoutLabels->addWidget(plblCompleted);

        QHBoxLayout* pHLayout = new QHBoxLayout();
        pMainLayout->addLayout(pHLayout);

        m_pwPending = new QListView(this);
        m_pwPending->setDragEnabled(true);
        m_pwPending->setAcceptDrops(true);
        m_pwPending->setDropIndicatorShown(true);
        m_pwPending->setDefaultDropAction(Qt::MoveAction);
        pHLayout->addWidget(m_pwPending);

        m_pwCompleted = new QListView(this);
        m_pwCompleted->setDragEnabled(true);
        m_pwCompleted->setAcceptDrops(true);
        m_pwCompleted->setDropIndicatorShown(true);
        m_pwCompleted->setDefaultDropAction(Qt::MoveAction);
        pHLayout->addWidget(m_pwCompleted);

        m_pwPending->setModel(new QStringListModel());
        m_pwCompleted->setModel(new QStringListModel());

        m_pwPending->setStyleSheet
        ("QListView { font-size: 20pt; font-weight: bold; }"
         "QListView::item { background-color: #E74C3C; padding: 10%;"
         "border: 1px solid #C0392B; }"
         "QListView::item::hover { background-color: #C0392B }");

        m_pwCompleted->setStyleSheet
        ("QListView { font-size: 20pt; font-weight: bold; }"
         "QListView::item { background-color: #2ECC71; padding: 10%;"
         "border: 1px solid #27AE60; }"
         "QListView::item::hover { background-color: #27AE60 }");


        QToolBar* pToolBar = new QToolBar(this);
        addToolBar(pToolBar);

        m_pActAdd = new QAction(this);
            m_pActAdd->setIcon(QIcon(":/resources/add.png"));
            connect(m_pActAdd, &QAction::triggered, this, &todolist::onAdd);

            m_pActRemove = new QAction(this);
            m_pActRemove->setIcon(QIcon(":/resources/remove.png"));
            connect(m_pActRemove, &QAction::triggered, this, &todolist::onRemove);

        pToolBar->addAction(m_pActAdd);
        pToolBar->addAction(m_pActRemove);

        setAcceptDrops(true);
}

void todolist::onAdd()
{
    m_pwPending->model()->insertRow(m_pwPending->model()->rowCount());
    QModelIndex oIndex = m_pwPending->model()->index(
    m_pwPending->model()->rowCount() - 1, 0);

    m_pwPending->edit(oIndex);

}

void todolist::onRemove()
{
    QModelIndex oIndex = m_pwPending->currentIndex();
    m_pwPending->model()->removeRow(oIndex.row());
}
void todolist::dropEvent(QDropEvent* event) {
    const QMimeData* mimeData = event->mimeData();
    QString temp;
    if(mimeData->hasText()) {
        temp = mimeData->text();
    }

    QMessageBox::information(this,"x",temp);
}

void todolist::dragEnterEvent(QDragEnterEvent *anEvent)
{
    anEvent->setAccepted(true);
}

void todolist::dragMoveEvent(QDragMoveEvent *anEvent)
{

}

void todolist::dragLeaveEvent(QDragLeaveEvent *anEvent)
{

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

QMimeData* ListModel::mimeData(const QModelIndexList& qMIndices) const {

  QMimeData* const pQMimeData = new QMimeData;
  QString qText;

  for (const QModelIndex& qMIndex : qMIndices) {
    qText += data(qMIndex, Qt::DisplayRole).toString() + "\n";
  }
  pQMimeData->setText(qText);

  std::cout << "1" << std::endl;
  draggedData = qText;
  return pQMimeData;
}

draggedData = qText; this line throws an error.


Solution

  • I used the recommended site Qt Doc. - Model/View Programming - Using Drag and Drop with Item Views to knit a small sample application for what OP asked.

    My MCVE testQListViewDragNDrop.cc:

    #include <QtWidgets>
    
    class ListModel: public QStringListModel {
    
      public:
        using QStringListModel::QStringListModel;
    
      protected:
        // for drag site
      
        // encodes dragged items (different from default).
        virtual QMimeData* mimeData(const QModelIndexList& qMIndices) const override;
        
        // for drop site
    
        // returns which kind of drop actions are supported.
        virtual Qt::DropActions supportedDropActions() const override
        {
          return Qt::MoveAction;
        }
    
        // checks whether certain dragged MIME data is droppable.
        virtual bool canDropMimeData(
          const QMimeData* pQMimeData, // dragged data
          Qt::DropAction action, // not evaluated
          int row, // not evaluated
          int column, // uninteresting for lists (but relevant for tables and trees)
          const QModelIndex& qMIndex) // uninteresting for lists (but relevant for trees)
          const override
        {
          return pQMimeData->hasText();
        }
    
        // drops dragged MIME data into model.
        virtual bool dropMimeData(
          const QMimeData* pQMimeData, // dropped data
          Qt::DropAction action, // not evaluated
          int row, // where to insert
          int column, // uninteresting for lists (but relevant for tables and trees)
          const QModelIndex& qMIndex) // uninteresting for lists (but relevant for trees)
          override;
    };
    
    QMimeData* ListModel::mimeData(const QModelIndexList& qMIndices) const
    {
      QMimeData* const pQMimeData = new QMimeData;
      QString qText;
      for (const QModelIndex& qMIndex : qMIndices) {
        qText += data(qMIndex, Qt::DisplayRole).toString() + "\n";
      }
      pQMimeData->setText(qText);
      return pQMimeData;
    }
    
    bool ListModel::dropMimeData(
      const QMimeData* pQMimeData, Qt::DropAction action,
      int row, int, const QModelIndex& qMIndex)
    {
      // get text from mime data
      const QString qText = pQMimeData->text().trimmed();
      if (qText.isEmpty()) return true;
      // split text into lines
      const QStringList qLines = qText.split(QChar('\n'));
      const int n = qLines.size();
      // fix row
      if (qMIndex.isValid()) row = qMIndex.row(); // dropped on row
      if (row < 0 || row > rowCount()) row = rowCount();
      // insert list into list model
      if (insertRows(row, n)) {
        for (const QString& qLine : qLines) {
          setData(index(row, 0), qLine);
        }
      }
      // done
      return true;
    }
    
    QStringList makeSampleData()
    {
      QStringList qList;
      qList
        << "Read the Qt doc."
        << "Write CMakeLists.txt"
        << "Write testQListViewDragNDrop.cc"
        << "Test and Debug"
        << "Fix bugs"
        << "Test and Debug"
        << "Fix bugs"
        << "Test and Debug"
        << "Fix bugs"
        << "Test and Debug"
        << "Fix bugs"
        << "Test and Debug"
        << "Fix bugs"
        << "Write SO answer";
      return qList;
    }
    
    int main(int argc, char** argv)
    {
      QApplication app(argc, argv);
      // setup GUI
      QWidget qWinMain;
      qWinMain.setWindowTitle("Test QListView Drag & Drop");
      qWinMain.resize(640, 480);
      QGridLayout qGrid;
      qGrid.addWidget(new QLabel("<b>To Do</b>"), 0, 0);
      qGrid.addWidget(new QLabel("<b>Done</b>"), 0, 1);
      qGrid.setRowStretch(1, 1);
      QListView qListToDo; // drag site
      ListModel qListModelToDo;
      qListModelToDo.setStringList(makeSampleData());
      qListToDo.setModel(&qListModelToDo);
      qListToDo.setDragEnabled(true); // allow drag in ToDo list
      qGrid.addWidget(&qListToDo, 1, 0);
      QListView qListDone; // drop site
      ListModel qListModelDone;
      qListDone.setModel(&qListModelDone);
      qListDone.viewport()->setAcceptDrops(true); // allow drops
      qListDone.setDropIndicatorShown(true); // adjust drop indicator
      qGrid.addWidget(&qListDone, 1, 1);
      qWinMain.setLayout(&qGrid);
      qWinMain.show();
      // run-time loop
      return app.exec();
    }
    

    Demo Session:

    GIF Animation of Demo Session

    Notes: