Fail to drop in a QListWidget



  • Hi,
    I have the following widget structure: a root QWidget contains a QFrame. The QFrame contains a QListWidget and a QTreeView. And, I want to drag-and-drop from the QTreeWidget to the QListWidget.

    But, as I do not want to subclass the QTreeView just for this, what I did is to connect the signal QTreeView::pressed to a slot that is on the root QWidget. This slott contains the following code:

    //-------------------------------------------------------------------------------
    void LoadView::slotInitiateDragAndDrop(const QModelIndex& p_index)
    //-------------------------------------------------------------------------------
    {
        // Initiate the drag operation
        QDrag*     drag     = new QDrag(this);
        QMimeData* mimeData = new QMimeData;
        mimeData->setText(static_cast<QFileSystemModel*>(m_ui.m_dirExplorer->model())->filePath(p_index));
        drag->setMimeData(mimeData);
        Qt::DropAction dropAction = drag->exec(Qt::CopyAction);
    }// slotInitiateDragAndDrop(const QModelIndex &p_index)
    

    On the other side, the QListWidget has the following configuration on its constructor:

        // Accept drop operation
        this->setAcceptDrops(true);
        this->setMouseTracking(true);
        this->setDropIndicatorShown(true);
    

    And I have reimplemented the dragEnterEvent, dragMoveEvent and dropEvent functions.

    Dragging operation is initiated (I see the indicator). But drop is not performed. In fact the QListWidget never enters in the reimplemented functions. I have checked that it is configured to accept copy action.

    So what I did wrong?

    Thanks for your help.



  • did you setDragDropMode(QAbstractItemView::DropOnly) on the listview?

    P.S.

    as I do not want to subclass the QTreeView just for this

    Hacking away a problem for "laziness" is bad. If you work in a team, this kind of things is what gets you a ton of 💩 dumped on. Particularly in this case where the subclassing solution is so much easier than your hack



  • @VRonin said in Fail to drop in a QListWidget:

    setDragDropMode(QAbstractItemView::DropOnly)

    Yes. But it does nothing. I also tried to apply the setAcceptDrops on the QLIstWidget::viewport(), as seen in a Wiki concerning the QLIstWidget. But it does nothing.

    The drag-and-drop process works well to drop in another application (I tried to drop in Notepad++) but not between these two stupid widgets. I also tried to create the drag object from the QTreeView. but this changes nothing.



  • To add: it seems to not be related to the fact the destination be a QListWidget. I have trie replacing it by a QLineEdit and it is still the same shit.


  • Qt Champions 2017

    Hi
    I tested your slotInitiateDragAndDrop way and it does work for me.
    for the custom listwidget i have

    void mylistwidget::dragEnterEvent(QDragEnterEvent* event) {
      event->acceptProposedAction();
    }
    
    void mylistwidget::dragMoveEvent(QDragMoveEvent* event) {
      event->acceptProposedAction();
    }
    
    void mylistwidget::dropEvent(QDropEvent* event) {
      qDebug() << event->mimeData()->formats();
      QByteArray itemData = event->mimeData()->data("text/plain");
      QDataStream dataStream(&itemData, QIODevice::ReadOnly);
      addItem( itemData );
      event->acceptProposedAction();
    }
    
    

    and
    alt text



  • Hi,
    So, this morning I did the following test:
    1- I have simplified the problem by managing a drag-and-drop internally to my widget. This is the code of the widget:

    #include "FavoriteListView.h"
    
    #include <QtGui/QDragEnterEvent>
    #include <QtGui/QDragMoveEvent>
    #include <QtGui/QDropEvent>
    
    #include <QtCore/QSettings>
    #include <QtCore/QStandardPaths>
    
    #include "VerboseTreeView.h"
    
    //----------------------------------------------------------------------------------------------------------------
    FavoriteListView::FavoriteListView(QWidget* p_parent /* = nullptr */)
        : QListWidget(p_parent)
    //----------------------------------------------------------------------------------------------------------------
    {
        m_favoriteFile = QStandardPaths::writableLocation(QStandardPaths::AppDataLocation) + "favorites.ini";
    
        QSettings favoriteFile(m_favoriteFile, QSettings::IniFormat);
    
        // Populate the list with default values
        QListWidgetItem* newItem;
        newItem = new QListWidgetItem(tr("Desktop"), this);
        newItem->setData(Qt::UserRole, QStandardPaths::writableLocation(QStandardPaths::DesktopLocation));
        this->addItem(newItem);
    
        newItem = new QListWidgetItem(tr("Documents"), this);
        newItem->setData(Qt::UserRole, QStandardPaths::writableLocation(QStandardPaths::DocumentsLocation));
        this->addItem(newItem);
    
        newItem = new QListWidgetItem(tr("User"), this);
        newItem->setData(Qt::UserRole, QStandardPaths::writableLocation(QStandardPaths::HomeLocation));
        this->addItem(newItem);
    
        for (auto currentKey : favoriteFile.allKeys())
        {
            // Add additional items
            QString currentData = favoriteFile.value(currentKey).toString();
            newItem = new QListWidgetItem(currentKey, this);     // Last name of the directory
            newItem->setData(Qt::UserRole, currentData);         // Full path
        }
    
        // Accept drop operation
        this->setMouseTracking(true);
        this->setAcceptDrops(true);
    }// FavoriteListView(QWidget* p_parent)
    
    //----------------------------------------------------------------------------------------------------------------
    FavoriteListView::~FavoriteListView()
    //----------------------------------------------------------------------------------------------------------------
    {
        QSettings favoriteFile(m_favoriteFile, QSettings::IniFormat);
    
        // remove previous favorites
        favoriteFile.clear();
    
        for (int i = 3; i < this->count(); ++i)
        {
            // Save the current item
            QListWidgetItem* currentItem = this->item(i);
            QString dataToSave = currentItem->data(Qt::UserRole).toString();
            favoriteFile.setValue(currentItem->text(), dataToSave);
        }
    
        favoriteFile.sync();
    }// ~FavoriteListView()
    
    //---------------------------------------------------------------------------------------
    void FavoriteListView::dragEnterEvent(QDragEnterEvent* p_event)
    //---------------------------------------------------------------------------------------
    {
        std::cout << "Mime Data: " << p_event->mimeData()->hasFormat("text/plain")
                  << "VerboseTreeView: " << dynamic_cast<VerboseTreeView*>(p_event->source())
                  << "Already present: " << this->isInFavorites(p_event->mimeData()->text()) << std::endl;
        p_event->acceptProposedAction();
    
        if ((p_event->mimeData()->hasFormat("text/plain")) &&                       // Content is text
            (dynamic_cast<VerboseTreeView*>(p_event->source()) != NULL) &&      // Source is a FileExplorerView
            (!this->isInFavorites(p_event->mimeData()->text())))  // Path is not in the favorites
        {
            // Accept the event
            p_event->acceptProposedAction();
        }// Accept the event
    }// dragEnterEvent ( QDragEnterEvent * event )
    
    //---------------------------------------------------------------------------------------
    void FavoriteListView::dragMoveEvent(QDragMoveEvent* p_event)
    //---------------------------------------------------------------------------------------
    {
        std::cout << "Mime Data: " << p_event->mimeData()->hasFormat("text/plain")
                  << "VerboseTreeView: " << dynamic_cast<VerboseTreeView*>(p_event->source())
                  << "Already present: " << this->isInFavorites(p_event->mimeData()->text()) << std::endl;
        p_event->acceptProposedAction();
    
        if ((p_event->mimeData()->hasFormat("text/plain")) &&                       // Content is text
            (dynamic_cast<VerboseTreeView*>(p_event->source()) != NULL) &&      // Source is a FileExplorerView
            (!this->isInFavorites(p_event->mimeData()->text())))  // Path is not in the favorites
        {
            // Accept the event
            p_event->acceptProposedAction();
        }// Accept the event
    }// dragMoveEvent ( QDragMoveEvent * event )
    
    //---------------------------------------------------------------------------------------
    void FavoriteListView::dropEvent(QDropEvent* p_event)
    //---------------------------------------------------------------------------------------
    {
        QString selectedString = p_event->mimeData()->text();
    
        if (selectedString != "")
        {
            QListWidgetItem* curItem = new QListWidgetItem(this);
            curItem->setText(QFileInfo(selectedString).fileName());
            curItem->setData(Qt::UserRole, QFileInfo(selectedString).absoluteFilePath());
            this->addItem(curItem);
        }// Something selected
    
        p_event->acceptProposedAction();
    }// dropEvent(QDropEvent *event)
    
    //---------------------------------------------------------------------------------------
    bool FavoriteListView::isInFavorites(const QString& p_path)
    //---------------------------------------------------------------------------------------
    {
        bool result = false;
        QString pathWithEnd = p_path + "/"; // to identify that d: and d:/ are the same dir
    
        for (int i = 0; i < this->count(); ++i)
        {
            // Search on each item
            QListWidgetItem* currentItem = this->item(i);
            QString fullPath = currentItem->data(Qt::UserRole).toString();
            result = result || (fullPath == p_path) || (fullPath == pathWithEnd);
        }
    
        return result;
    }// isInFavorites(const std::string &p_path)
    
    
    //-------------------------------------------------------------------------------
    void FavoriteListView::mousePressEvent(QMouseEvent* event)
    //-------------------------------------------------------------------------------
    {
        // Initiate the drag operation
        QDrag*     drag = new QDrag(this);
        QMimeData* mimeData = new QMimeData;
        mimeData->setText("fait chier");
        drag->setMimeData(mimeData);
        Qt::DropAction dropAction = drag->exec(Qt::CopyAction);
    }// slotInitiateDragAndDrop(const QModelIndex &p_index)
    
    

    2- If I put this widget in a QDialog (that run in modal mode) everything works well.

    3- But if the widget is a part of my QMainWindow (in my widget hierachy) this does not work. None of the drag event function is called. My widget hierarchy is the following (parenting)

    LoadView (QWidget) ==> QFrame ==> FavoriteListView (QListWidget)

    The LoadView has no parent. And it is in a QStackedWidget. The hierarchy of the stacked widget is:

    QMainWindow ==> QWidget ==> QStackedWidget

    So, there is someone, in this structure, that blocks the drag events.



  • OK,
    I have reproduced the whole hierarchy structure in my QDialog. And in this case everything works well. This helps me to find were the problem is. It is somewhere in the DoDragDrop() function. This one, for an unkonwn reason never call QWindowsOleDropTarget::HandleDrag when the widget is in my QMainWindow.

    Unfortunately, as DoGrapAndDrop is a Windows function I have no access to its code.

    @Addendum: I'm on Windows10 with Qt 5.6.3.



  • OK,
    Finally the problem has been found. In a part of the code there has some calls to COM functions. The routine called CoInitializeSecurity() and CoUninitialized(). By commenting these two functions everything works well now.


Log in to reply
 

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