在两个QTreeWidget之间拖放

时间:2013-06-24 19:09:36

标签: qt drag-and-drop qtreewidget qtreewidgetitem

我的问题是我有两个QTreeWidgets,我想从一个拖放到另一个(反之亦然)。我可以拖放QTreeWidgetItems,但是,当我删除一个有子节点的QTreeWidgetItem时,我丢失了它们,只丢弃了父节点。

我真的不知道该怎么做。我找到的唯一方法是重新实现dropEvent并销毁所有丢弃的对象并重新构建它们。但是我不喜欢这个解决方案,因为它很慢并且对象不一样,所以它非常复杂撤消/重做功能的实现...

嗯,这就是我所拥有的:

#include <QApplication>
#include <QDebug>
#include <QObject>
#include <QWidget>
#include <QString>
#include <QTextStream>
#include <QIODevice>
#include <QMainWindow>
#include <QVBoxLayout>


#include "KTreeWidget.h"
#include "KAbstractItem.h"
#include "KItem.h"
#include "KItemGroup.h"

int main(int argc, char* argv[]){

 QApplication app(argc, argv);

 QMainWindow *window = new QMainWindow();
 QWidget* central = new QWidget(window);
 QVBoxLayout *layout = new QVBoxLayout();

 KTreeWidget* kv = new KTreeWidget(window);
 KTreeWidget* trash = new KTreeWidget(window);

 layout->addWidget(kv);
 layout->addWidget(trash);

 central->setLayout(layout);

 KItem* kiarr[5];
 for (int i = 0 ; i < 5 ; i++){
  kiarr[i] = new KItem(kv);
  kiarr[i]->setText(0,QString("Item %1").arg(i));
 }
 KItemGroup* kgarr[5];
 for (int i = 0 ; i < 5 ; i++){
  kgarr[i] = new KItemGroup(trash);
  kgarr[i]->setText(0,QString("Group %1").arg(i));
 }

 window->setCentralWidget(central);
 window->show();

 return app.exec();
}

我的QTreeWidget: KtreeWidget.h

#ifndef _KTW_H_
#define _KTW_H_

#include <QTreeWidget>

class KTreeWidget: public QTreeWidget{
 Q_OBJECT

private:
 QTreeWidgetItem* _header;

public:
 KTreeWidget(QWidget* w = NULL);
};

#endif

和KTreeWidget.cc:

#include "KTreeWidget.h"

KTreeWidget::KTreeWidget(QWidget* w):QTreeWidget(w){
 setColumnCount(3);
 _header = new QTreeWidgetItem(NULL);
 _header->setText(0,"Title");
 _header->setText(1,"Edit");
 _header->setText(2,"Open");
 this->setDefaultDropAction(Qt::MoveAction);
 setHeaderItem(_header);
 setDragEnabled(true);
 setAcceptDrops(true);
}

和项目(3个类,以区分组和叶子): KAbstractItem.h

#ifndef _KABSI_H_
#define _KABSI_H_

#include <QObject>
#include <QTreeWidgetItem>
#include <QTreeWidget>

class KAbstractItem : public QObject, public QTreeWidgetItem{
 Q_OBJECT
public:
 KAbstractItem(QTreeWidget* p = NULL);
};

#endif

和KAbstractItem.cc

#include "KAbstractItem.h"
KAbstractItem::KAbstractItem(QTreeWidget* p):QTreeWidgetItem(p){}

KItem.h

#ifndef _KI_H_
#define _KI_H_

#include "KAbstractItem.h"

class KItem : public KAbstractItem{
 Q_OBJECT
public:
 KItem(QTreeWidget* p);
};

#endif

和KItem.cc

#include "KItem.h"

KItem::KItem(QTreeWidget* p):KAbstractItem(p){
 setFlags(Qt::ItemIsSelectable 
  | Qt::ItemIsEditable 
  | Qt::ItemIsDragEnabled
  | Qt::ItemIsUserCheckable
  | Qt::ItemIsEnabled);
}

和KItemGroup.h

#ifndef _KIG_H_
#define _KIG_H_

#include "KAbstractItem.h"

class KItemGroup : public KAbstractItem{
 Q_OBJECT
public:
 KItemGroup(QTreeWidget* p);
};

#endif

和KItemGroup.h     #include&#34; KItemGroup.h&#34;

KItemGroup::KItemGroup(QTreeWidget* p):KAbstractItem(p){
 setFlags(Qt::ItemIsSelectable 
    | Qt::ItemIsEditable 
    | Qt::ItemIsDragEnabled
    | Qt::ItemIsDropEnabled
    | Qt::ItemIsUserCheckable
    | Qt::ItemIsEnabled);
}

每当我在第一个WTreeWifget中的一个项目中删除第二个组中的一个组时,它就可以了,但是然后我将一个组移到顶部QTreeWidget,我失去​​了所有的孩子......

你告诉我我做错了吗? 提前谢谢!

2 个答案:

答案 0 :(得分:1)

所以,我检查过它并没有按要求工作,你没有做错任何事。

我似乎问题是QAbstractItemModel(在QTreeWidget relies中对内部拖动的数据进行编码)mimeData()方法is not considering nested items(它只是编码行+列,但不是父

甚至可能是视图只是将拖动项的QModelIndex传递给mimeData,想想,它可能会更好,因为不考虑父信息...

我看到的唯一解决方案是重新实现dropevent。但你不必破坏这些物品。 使用

QTreeWidgetItem * QTreeWidgetItem::takeChild ( int index ) QTreeWidgetItem * QTreeWidget::takeTopLevelItem ( int index )

采取拖动的项目

void QTreeWidgetItem::insertChild ( int index, QTreeWidgetItem * child )

放弃它

我已经检查过这种方式,孩子们是正确的。 (见this gist

答案 1 :(得分:0)

这是我解决它的方式: 当您拖放时,At创建一个新对象,与您的文本相同的值不同,但是它是另一个对象,只是删除了你的对象,但是没有释放内存。

要做的第一件事就是覆盖removeChild,因为它基于索引而不是地址,所以它不能很好地用于我们将要做的事情。 (http://sourceforge.net/p/ckmapper/code/4/tree/trunk/src/KViewer/KAbstractItem.cc#l39

然后我们需要做的是覆盖QTreeWidget的dropEvent。战术如下:

  1. 获取应该被拖动的所有选定项目但不是Qt。
  2. 允许Qt进行删除。
  3. 在目标上查找可能包含Qt创建的新对象的项目。这可以通过itemAt(event-&gt; pos)完成。
  4. 在那些项目的孩子中查找哪些是丢弃的项目:这可以通过dynamic_cast&lt;&gt;来完成。因为Qt创建的是ATreeWidgetItems而我们继承自这个类。
  5. 获取其索引。
  6. 删除“寄生虫”项目,然后将其删除。
  7. 将所选项目插入寄生虫的索引。
  8. 我们必须重写removeChild,因为WE正在手动删除子项(所选项目),而Qt正在删除它应该删除的项目(也不是选定的项目)(但它没有)。因此,如果您检查Qt代码,您将看到它基于索引,这不安全,而根据其地址删除项目更安全。 我会在这里发布我的代码,我忘了提交它;)

    无论如何,Trompa的解决方案也是有效的,对我来说似乎更简单。我也想分享我的解决方案;)