PDA

View Full Version : Dropping files from the windows explorer into a subclassed QTreeWidget



paltomare
14th April 2006, 12:30
Hi
I try to implement to drop files from the windows explorer to a QTreeWidget (this one is subclassed clsMyTree (I need such feature to open the files and extract data to fill the tree).
The problem that I have is that couldn't found any way to accept the QTreeWidget to see the drop object.
See some test class below:

///////////////////start class //////////////////////////
///////////header file//////
#include <QtGui/QApplication>
#include <QtGui/QTreeWidget>
class clsMyTree :
public QTreeWidget
{
Q_OBJECT
public:
clsMyTree(void);
clsMyTree( QWidget *p=0); //: QTreeWidget(p) { }
virtual ~clsMyTree(void);
protected:
virtual bool event(QEvent *event);
virtual bool dropMimeData ( QTreeWidgetItem * parent, int index, const QMimeData * data, Qt::DropAction action );
public slots:
void setValue();

signals:
void valueChanged(int newValue);
};

///////////cpp file//////
#include "heaMyTree.h"
#include <QDropEvent>
clsMyTree::clsMyTree(void)
{
}
clsMyTree::clsMyTree( QWidget *p) : QTreeWidget(p) {
setAcceptDrops(true);
p->setAcceptDrops(true);
}

clsMyTree::~clsMyTree(void)
{
}

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

bool clsMyTree::event(QEvent *event)
{
if (event->type() == QEvent::Drop) {
QDropEvent *pEv=static_cast<QDropEvent *>(event);
Qt::DropAction dropAct=pEv->dropAction ();
long lActio=0;
lActio=dropAct;
}

return QWidget::event(event);
}


void clsMyTree::setValue()
{

}
///////////////////end class //////////////////////////
With this example I catch one file from the windows explorer and try to drop it into the clsMyTree(inherited from QTreeWidget) and no event happen in my reimplemented functions ::event,dropMimeData and so on. Nor he display me the right mousecursor.
For me it looks like the widget are not right enabled for dropping objects that are
incomming out from another application. In this case windows explorer.
I there somebody that have experience with such kind of works?
Is the QTreeWidget the right widget for such things and is my implementation right or maybe I forgote something others?

PS: The example was done with QT 4.1 and Visual Studio 2003. For the main
widget I use also the designer. But unfortunately the new designer is for
such works, especially for this drag and drop problem, not really
helpfully.
In the mean time I try to do this with KDevelop and KDE in Linux.
I would really appreciate any helps.

Thanks

Piero

wysota
14th April 2006, 13:48
I don't see the drop actually implemeneted anywhere in the code you have shown. Does the widget accept the drop or does it show the "stop sign"? You have to make sure it accepts appropriate mime-types (in case of files you'll get text/uri-list).

paltomare
14th April 2006, 14:38
Yes u have right. I could implement the drop (by examing the mime type and so on..) event, but the problem that have manifest earlier. As explaint before, when I start the drop action (by moving the mouse with the drag object over the QTreeWidget) in never function, espacially in the event function should be at least pass one of the overloaded functions ( I testet this in debug mode with break points in the following functions: event, dropEvent, dropMimeData). With this approach, I was also testing other drag & drops implentation with QT, and this was working.
In my opinion the QTreeWidget is not ready to accept any drops, because the mouse cursor over the QTreeQidget does not change the Icon (shown that this object accept some drops).
You have some another idea, or u see some other mess?
I spent a lot of time and patience in it. I'm able to drag and drop object insight of the program, but I'm not able to communicate with drag and drop objects with QTreeWidget with other programms. And really I don't know where could be the diffrerence.:confused:

paltomare
14th April 2006, 16:28
Aha, I found aout that I have to implement de dragEnterEvent function.

void clsMyTree::dragEnterEvent ( QDragEnterEvent * event ){
if(event->mimeData()->hasUrls()==true){
event->acceptProposedAction();
QDrag *drag = new QDrag(this);
QMimeData *mimeData = new QMimeData;
QString qstrType;
qstrType=event->format(0);

mimeData->setData(qstrType , event->mimeData()->data(qstrType));
drag->setMimeData(mimeData);

Qt::DropAction dropAction = drag->start(Qt::CopyAction | Qt::MoveAction);
event->acceptProposedAction();
}
}
After this the dropMimeData function is called. But I'm not sure if this is the correct way.
First it talkes a while until the function dropMimeData is called and second the mouse curosr resp. icon is still the blocked icon.
Should I also changed the mouse icon ?
This would be not so nice:( .

fullmetalcoder
14th April 2006, 16:40
You're doing it the bad way!!!

Do NOT subclass events unless you have a revolutionnar D & D concept to implement! Everything is already done, all you need is to subclass :


virtual bool dropMimeData( QTreeWidgetItem *parent, const QMimeData *data, Qt::DropAction action)


You may also want to read the docs to understand how to use it... :p

paltomare
14th April 2006, 19:04
Sorry, but what you are talking is wrong!
I did this exactly what you wrote before! In this way u could not receive any dropMimeData event if u want drag & Drop files from the windows explorer.
I read also the docs, but nothing about such explanation.
I donn't have problem with the drag & drops problem, but I have problem to drops files from outside of my program into to my QTreeWidget ;) .
Tell me more and not send me just one function what anyway my self already found in the documentation!

wysota
14th April 2006, 23:45
You really don't have to touch the event handlers here. All you need is already implemented by the abstract view class -- take a look at its sources, if you don't believe us, for example:


void QAbstractItemView::dragEnterEvent(QDragEnterEvent *event)
{
if (d_func()->canDecode(event)) {
event->accept();
setState(DraggingState);
} else {
event->ignore();
}
}

All things you need to reimplement are:

bool QTreeWidget::dropMimeData ( QTreeWidgetItem * parent, int index, const QMimeData * data, Qt::DropAction action ) [virtual protected]
Handles the data supplied by a drag and drop operation that ended with the given action in the index in the given parent item.
See also supportedDropActions().

QStringList QTreeWidget::mimeTypes () const [virtual protected]
Returns a list of MIME types that can be used to describe a list of treewidget items.
See also mimeData().

QMimeData * QTreeWidget::mimeData ( const QList<QTreeWidgetItem *> items ) const [virtual protected]
Returns an object that contains a serialized description of the specified items. The format used to describe the items is obtained from the mimeTypes() function.
If the list of items is empty, 0 is returned rather than a serialized empty list.

First method does the actual drop, second returns a list of mime-types which can be dropped onto the widget (maybe you forgot to implement it -- that's why I asked about that "stop sign" in my previous post) and the last one returns a pointer to an object describing a particular item according to mime-types returned by the previous method.

You can take a look at equivalents of those three methods in the QAbstractItemModel class. And also remember that QTreeWidget is just a wrapper over QTreeView containing an internal model representation. For example:

bool QTreeWidget::dropMimeData(QTreeWidgetItem *parent, int index,
const QMimeData *data, Qt::DropAction action)
{
QModelIndex idx;
if (parent) idx = indexFromItem(parent);
return model()->QAbstractItemModel::dropMimeData(data, action , index, 0, idx);
}

paltomare
17th April 2006, 14:57
Yes, you got right !!!
I had to implement the mimeTypes with the right mime type. This is what was missing.
QStringList clsMyTree::mimeTypes () const{
QStringList qstrList;
//loading of mime types should be loaded over a ini files
//here I hardcode this part
qstrList.append("application/x-qabstractitemmodeldatalist");
qstrList.append("text/html");
qstrList.append("text/plain");
qstrList.append("text/uri-list");
qstrList.append("text/directory");
qstrList.append("text/xml");
return qstrList;
}

This is this part where I never understood.
Thanks so much for your good explanation :) :)