PDA

View Full Version : QTreeWidget Drag and Drop



tommydent
11th August 2008, 11:00
Hello,

I have a problem, with drag and drop in a qtreewidget. I try to use drag in drop inside a QTreewidget (qt version 4.3.3). I found this simple tutorial (see "Drop to customized QTreeWidget") on the web:

http://sector.ynet.sk/qt4-tutorial/dnd.html

It works, but there is a problem, that was already mentioned (but not answered) in:

http://www.qtcentre.org/forum/f-newbie-4/t-qtreewidget-drag-and-drop-5910.html

For a CopyAction, the dropMimeData function is called, and I can use the QMimeData do get the information I need. For a MoveAction (i.e. if the Shift Key is pressed while dragging&dropping) the dropMimeData function is not called - but anyhow the dragged/dropped items are moved in the QTreeWidget. The behaviour of the dragging and dropping is "nearly" as expected, but I am not able to "react" to MoveActions.

Is it a bug or a feature that the dropMimeData function is not called for MoveActions? If it is a bug, is it already fixed? If it's a feature - what is the correct way to get in control of "what happens after a MoveAction"?

Thank you very much in advance!

Tdent

wysota
12th August 2008, 02:30
Could you prepare a minimal compilable example reproducing the problem? I've used MoveActions with models and they worked just fine - dropMimeData was called.

tommydent
22nd August 2008, 13:52
Hi,

sorry it took so long. Here is my (very simple) tree widget


----------------------------------------------------------------------------



#include "myQTTreeWidget.h"

#include <QDragEnterEvent>
#include <QDragMoveEvent>
#include <QList>


myQTTreeWidget::myQTTreeWidget(QWidget* parent)
: QTreeWidget(parent)
{
setAcceptDrops(true);
setDragEnabled(true);

setDragDropMode(QAbstractItemView::DragDrop);
setSelectionMode(QAbstractItemView::ExtendedSelect ion);
setEditTriggers(QAbstractItemView::SelectedClicked );

setHeaderLabel("Name");
setColumnCount(1);

QTreeWidgetItem *item1 = new QTreeWidgetItem(this);
QTreeWidgetItem *item2 = new QTreeWidgetItem(this);
QTreeWidgetItem *item3 = new QTreeWidgetItem(this);
QTreeWidgetItem *item4 = new QTreeWidgetItem(this);

item1->setText(0,"hello");
item2->setText(0,"world!");
item3->setText(0,"whats");
item4->setText(0,"up?");

}

myQTTreeWidget::~myQTTreeWidget()
{
}

void myQTTreeWidget::dragEnterEvent(QDragEnterEvent *e)
{
e->accept();
}

void myQTTreeWidget::dragMoveEvent(QDragMoveEvent *e)
{
e->accept();
}

QMimeData *myQTTreeWidget::mimeData(const QList<QTreeWidgetItem *> items) const
{
return new QMimeData;
}

bool myQTTreeWidget::dropMimeData ( QTreeWidgetItem * newParentPtr, int index, const QMimeData * data, Qt::DropAction action )
{
return true;
}

Qt::DropActions myQTTreeWidget::supportedDropActions () const
{
return Qt::CopyAction|Qt::MoveAction;
}


-----------------------------------------------------------------------------

If you want to reproduce the behaviour, you can place a breakpoint into dropMimeData (or some kind of fprintf(...) output :rolleyes:). You will see that this function is called if you try to drag & drop one of the items (without pressing Shift!). But it is not called if you press the Shift key while you're dragging/dropping the item. If you try to drag&drop an item without pressing Shift - nothing happens after dropping the item (that's ok, the drop function is empty). If you drag&drop an item while the Shift key is pressed, then the item is moved after dropping it (wherever this behaviour is implemented).

Maybe there is something totally wrong with my code. Maybe I made something very stupid? Any suggestion is very welcome.

Thanks, take care

tommydent
22nd August 2008, 16:59
I added the following lines:



void myQTListView::dropEvent( QDropEvent *e )
{
fprintf(stderr,"dropped\n");
QTreeWidget::dropEvent(e);
}


The dropEvent is called but it does not reach the dropMimeData funtion. I guess I have to build some qt debug libs...

But still: Any suggestion is very wellcome.

jpn
23rd August 2008, 11:06
QAbstractItemModel::dropMimeData() is called by QAbstractItemView::dropEvent() so reimplementing dropEvent() without calling the base class implementation prevents dropMimeData() from being called. Furthermore, reimplementing other drag and drop related event handlers, again, without calling the base class implementation like in the code above, prevents QAbstractItemView DND from functioning properly. Take a look at src/gui/itemviews/qabstractitemview.cpp and see what QAbstractItemView::dragEnterEvent() and QAbstractItemView::dragMoveEvent() do. Writing:


void myQTTreeWidget::dragEnterEvent(QDragEnterEvent *e)
{
e->accept();
}

void myQTTreeWidget::dragMoveEvent(QDragMoveEvent *e)
{
e->accept();
}

overrides all that functionality with.. nothing. :)

ram136682
24th August 2008, 05:39
Greetings ,

In the two functions below override the original events by accepting the event but what next.

It will accept the event and no action is performed. ( Try emitting a signal within these functions and perform the required actions accordingly )

void myQTTreeWidget::dragEnterEvent(QDragEnterEvent *e)
void myQTTreeWidget::dragMoveEvent(QDragMoveEvent *e)

Regards
-Ram

wysota
24th August 2008, 21:24
Is it a continuation of the same problem by a different forum user, a completely separate issue or an answer to the original problem? I got completely lost here... :confused:

tommydent
25th August 2008, 10:27
Thank you very much for your help.

Even if it's a very silly question, I have to ask it (sorry 'bout that):

Whats the "correct" way to implement the dragEnterEvent and dragMoveEvent functions - is this the way?




void myQTTreeWidget::dragEnterEvent(QDragEnterEvent *e)
{
// always call base class implementation
QTreeWidget::dragEnterEvent(e);

if ( isDragEnterPossible(e) )
{
e->accept();
}
else
{
e->ignore();
}
}

void myQTTreeWidget::dragMoveEvent(QDragMoveEvent *e)
{
// always call base class implementation
QTreeWidget::dragMoveEvent(e);

if ( isDragMovePossible(e) )
{
e->accept();
}
else
{
e->ignore();
}
}


isDragMovePossible and isDragEnterPossible are member functions, returning a bool value and telling us if dropping is possible.

wysota
25th August 2008, 11:45
The question is why would you want to reimplement them? What's wrong with the default implementation?

tommydent
25th August 2008, 14:10
Thank you for your answer.

So "what is this all about":

I have an application with lots of different widgets (treeviews, listviews, iconviews .... ). All widgest support dnd (all of them are still old qt3 style, but will/should (:rolleyes:) be "converted" soon). In my (derived) QTreeView I want do accept the drags from some of the other widgets, but not from all of the other widget. I thought the dragEnterEvent can (has to) be used for defining which events are accepted and which are not:



void myQTListView::dragEnterEvent(QDragEnterEvent *e)
{
if ( e )
{
if ( e->provides("mystuff/mything") )
{
e->accept();
}
else
{
e->ignore();
}
}
}




I also have different items (all derived from QTreeWidgetItem of course) in my treeview. Some of them accept drops and some of them don't. So I use the dragMoveEvent to get the "current dropping target" by calling



void myQTListView::dragMoveEvent(QDragMoveEvent *e)
{
QTreeWidgetItem *item = itemAt(e->pos());

bool accept = false;

if ( item )
{
if ( dynamic_cast<MySpecialListViewItem*>(item) )
{
accept = true;
}
}

if ( accept )
{
e->accept();
}
else
{
e->ignore();
}
}


and check (by dynamic cast) if this (derived) QTreeWidgetItem is one of the items that accept drops.

I use the event->accept() or event->ignore() function to indicate if dropping is possible or not.

ps. Sorry that this has become a beginner tutorial on using drag and drop with QTreeViews, maybe I was running completely in the wrong direction?

wysota
25th August 2008, 15:25
But most of what you want is already implemented by default handlers, there is no need to reinvent the wheel. You can tell the widget which types of data it should accept. Take a look at mimeTypes(), mimeData() and dropMimeData().