2

我的问题是我有两个 QTreeWidget,我想从一个拖放到另一个(反之亦然)。我可以拖放 QTreeWidgetItems,但是,当我放下一个有孩子的 QTreeWidgetItem 时,我会失去它们,只有父母会被丢弃。

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

好吧,这就是我所拥有的:

#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 "KItemGroup.h"

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

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

你能告诉我我做错了什么吗?提前致谢!

4

2 回答 2

1

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

我似乎的问题是 QAbstractItemModel (其中 QTreeWidget依赖于在内部对拖动的数据进行编码)mimeData()方法没有考虑嵌套项(它只编码行+列,但不编码父项。

甚至可能该视图仅将拖动项目的 QModelIndex 传递给 mimeData,认为这样可能会更好,因为不考虑父信息...

我看到的唯一解决方案是重新实现 dropevent。但您不必销毁这些物品。采用

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

获取拖动的项目

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

放下它

我已经检查过这种方式孩子们是正确的。(见这个要点

于 2013-06-26T07:17:19.020 回答
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->pos) 来完成。
  4. 在这些项的子项中查找哪些是被丢弃的项:这可以通过 dynamic_cast<> 来完成,因为 Qt 创建的项是 ATreeWidgetItems 而我们的继承自此类。
  5. 获取它的索引。
  6. 删除“寄生虫”项目,并将其删除。
  7. 在寄生虫的索引处插入选定的项目。

我们需要覆盖 removeChild,因为我们正在手动删除子项(选定的项目),而 Qt 正在删除应该删除的项目(也是选定的项目)(但它没有)。因此,如果您检查 Qt 代码,您会发现它基于索引,这是不安全的,而基于地址删除项目更安全。我稍后会在这里发布我的代码,我忘了提交它;)

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

于 2013-07-12T13:59:34.750 回答