Important: Please read the Qt Code of Conduct - https://forum.qt.io/topic/113070/qt-code-of-conduct

QListView in a QTabWidget tab - External Drop Not Working



  • Hey Gurus,
    I just can't seem to get this working.
    I have a QTabWidget created in QT's form designer (ui->chatTabs). As required I add tabs (ChatTab) to the widget. Any tabs added are based on QWidget class.

    chattab.h

    class ChatTab : public QWidget
    {
    	Q_OBJECT
    public:
    	explicit ChatTab(STClientSettings *settings, QString chatUUID, QWidget *parent = nullptr);
    	~ChatTab();
    
    ...
    };
    
    #endif // CHATTAB_H
    

    chattab.cpp

    ChatTab::ChatTab(struct STClientSettings *settings, QString chatUUID, QWidget *parent) : QWidget(parent)
    {
    	m_settings = settings;
    	m_chatTabUUID = chatUUID;
    
    	m_chatList = new SQListView;
    
    	m_chatList->setResizeMode(QListView::Adjust);
    	m_chatList->setWordWrap(true);
    	m_chatList->setVerticalScrollMode(QAbstractItemView::ScrollPerPixel);
    	m_chatList->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
    	m_chatList->setModel(&m_mymodel);
    	m_chatList->setMinimumSize(700,400);
    	m_chatList->setSelectionMode(QAbstractItemView::SingleSelection);
    
    	m_chatList->setAcceptDrops(true);
    	m_chatList->setDropIndicatorShown(true);
    
    	connect( m_chatList, SIGNAL(doubleClicked(const QModelIndex &)), this, SLOT(chatListDoubleClicked(const QModelIndex &)));
    
    	// Capture context menu clicks...
    	m_chatList->setContextMenuPolicy(Qt::CustomContextMenu);
    
    	// ...and send those clicks to CustomMenuRequested
    	connect(m_chatList, SIGNAL(customContextMenuRequested(QPoint)), SLOT(ListMenuRequested(QPoint)));
    
    	// NOW tell the view to rely on our custom delegate for drawing
    	m_chatList->setItemDelegate(new ChatBubbleDelegate());
    ...
    	listsLayout->addWidget(m_chatList);
    ...
    	mainLayout->addLayout(listsLayout);
    	mainLayout->addLayout(messageLayout);
    	mainLayout->addLayout(swapLayout);
    	mainLayout->addLayout(quickReplyLayout1);
    	mainLayout->addLayout(quickReplyLayout2);
    
    	setLayout(mainLayout);
    }
    

    SQlistView is my QListView overridden class:

    sqlistview.h

    #ifndef SQLISTVIEW_H
    #define SQLISTVIEW_H
    
    #include <QObject>
    #include <QWidget>
    #include <QListView>
    
    class SQListView : public QListView
    {
    public:
    	SQListView();
    
    protected:
    	 void dropEvent(QDropEvent *ev) override;
    };
    
    #endif // SQLISTVIEW_H
    

    sqlistview.cpp

    #include "sqlistview.h"
    
    #include <QDebug>
    
    SQListView::SQListView()
    {
    
    }
    
    void SQListView::dropEvent(QDropEvent *ev)
    {
    	qDebug() << "file dropped";
    }
    

    A chattab is added to the QTabWidget like this:

    	ChatTab *chatTab = new ChatTab( &m_settings, uuid, this );
    
    	// Add the new tab to the tab widget
    	index = ui->chatTabs->addTab( chatTab, "Chat Room" );
    
    	// Activate the new tab
    	ui->chatTabs->setCurrentIndex( index );
    

    No matter what I do, dropping a file onto the SQListView won't work. The drop indicator always has the circle with the line through it, indicating I can't drop.

    As you can see, my SQListView also has a custom delegate, I thought this may be causing issues, but disabling it changes nothing.

    I just want to be able to drop an external file onto SQListView, I don't need to use the interal drag and drop within the list.

    Could someone please give me some idea of what I may be doing wrong?

    Thanks heaps in advance.

    Steve Q. :-)


  • Lifetime Qt Champion



  • @jsulm I just tested it and acceptDrops resolves to true.
    Still drop does not work?


  • Lifetime Qt Champion

    Hi,

    The Model/View classes have already support for drag and drop. Therefore you have more specific methods to override in order to customise your model/view behaviour to your liking.

    See the dedicated chapter in Qt's documentation especially the mimeTypes, canDropMimeData and dropMimeData methods of your model class.



  • @SGaist Thanks heaps for the heads up.
    I'll have a read of this and see how I go.



  • @SGaist Hi Again,
    I have read this documentation, and I'm still not sure how to proceed. I've modified my code to include this:

    	m_chatList->setAcceptDrops(true);
    	m_chatList->setDragEnabled(false);
    	m_chatList->setDropIndicatorShown(true);
    	m_chatList->viewport()->setAcceptDrops(true);
    	m_chatList->setDragDropMode(QAbstractItemView::DropOnly);
    

    But the SQListViewstill gives me the round circle with the line through it, indicating I can't drop.

    I'm sorry to be a pain, but could you please give me more of an idea of what to do?

    I'm obviously missing something here, but I just don't know what it is!

    Thanks so much,

    Steve Q.



  • @SGaist I have managed to get drag and drop working on the entire widget, which will be fine for now.
    But I still can't get it to work on ONLY the listview in the widget.

    I have change my SQListView code to the following:

    sqlistview.cpp

    #include "sqlistview.h"
    
    #include <QDebug>
    #include <QDragEnterEvent>
    #include <QMimeData>
    
    SQListView::SQListView()
    {
    	viewport()->setAcceptDrops(true);
    }
    
    void SQListView::dropEvent(QDropEvent* e)
    {
    
    	foreach (const QUrl &url, e->mimeData()->urls())
    	{
    		 QString fileName = url.toLocalFile();
    		 qDebug() << "Dropped file:" << fileName;
    	}
    }
    
    void SQListView::dragEnterEvent(QDragEnterEvent *e)
    {
    	if (e->mimeData()->hasUrls())
    	{
    		e->acceptProposedAction();
    	}
    }
    

    sqlistview.h

    #ifndef SQLISTVIEW_H
    #define SQLISTVIEW_H
    
    #include <QObject>
    #include <QWidget>
    #include <QListView>
    
    class SQListView : public QListView
    {
    public:
    	SQListView();
    
    private slots:
    	void dragEnterEvent(QDragEnterEvent *e);
    	void dropEvent(QDropEvent *ev);
    
    protected:
    };
    
    #endif // SQLISTVIEW_H
    

    and in the creation of the listview:

    	m_chatList = new SQListView;
    
    	m_chatList->setResizeMode(QListView::Adjust);
    	m_chatList->setWordWrap(true);
    	m_chatList->setVerticalScrollMode(QAbstractItemView::ScrollPerPixel);
    	m_chatList->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
    	m_chatList->setModel(&m_mymodel);
    	m_chatList->setMinimumSize(700,400);
    	m_chatList->setSelectionMode(QAbstractItemView::SingleSelection);
    
    	connect( m_chatList, SIGNAL(doubleClicked(const QModelIndex &)), this, SLOT(chatListDoubleClicked(const QModelIndex &)));
    
    	// Capture context menu clicks...
    	m_chatList->setContextMenuPolicy(Qt::CustomContextMenu);
    
    	// ...and send those clicks to CustomMenuRequested
    	connect(m_chatList, SIGNAL(customContextMenuRequested(QPoint)), SLOT(ListMenuRequested(QPoint)));
    
    	// NOW tell the view to rely on our custom delegate for drawing
    	m_chatList->setItemDelegate(new ChatBubbleDelegate());
    

    But still no luck!

    Steve Q. :-)


  • Lifetime Qt Champion

    It's your model that you have to modify to support other mime types etc.



  • @SGaist Ahhh okay. Thanks for the tip. Back to the docs it is for me!



  • Hi all,

    I have now solved this.

    As my drop was not item dependent, that is I didn't care what was under the drop, so long as it was the list, I didn't need to subclass the QStandardItemModel. Instead I simply subclassed the QListView with the following overridden methods:

    	void dragEnterEvent(QDragEnterEvent *e);
    	void dropEvent(QDropEvent *ev);
    	void dragMoveEvent(QDragMoveEvent* event);
    

    I can now drop on my list and I will receive the filename of the file that was dropped. I then "emit" this filename to my parent to act on it accordingly.

    Thanks for all your help.

    Steve Q. :-)


Log in to reply