Qt 在两个小部件之间拖放

Qt 在两个小部件之间拖放,qt,drag-and-drop,qtreewidget,qtreewidgetitem,Qt,Drag And Drop,Qtreewidget,Qtreewidgetitem,我的问题是我有两个QTreeWidget,我想从一个到另一个进行拖放(反之亦然)。我可以拖放QTreeWidgetItems,但是,当我拖放一个有子项的QTreeWidgetItem时,我会丢失子项,并且只会拖放父项 我真的不知道怎么做。我找到的唯一方法是重新实现dropEvent,销毁所有被丢弃的对象并重新构建它们。。但我不喜欢这个解决方案,因为它速度慢,对象也不一样,所以它使撤销/重做功能的实现变得非常复杂 这就是我所拥有的: #include <QApplication> #i

我的问题是我有两个QTreeWidget,我想从一个到另一个进行拖放(反之亦然)。我可以拖放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();
}
和项目(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
基特姆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::KItemGroup(QTreeWidget* p):KAbstractItem(p){
 setFlags(Qt::ItemIsSelectable 
    | Qt::ItemIsEditable 
    | Qt::ItemIsDragEnabled
    | Qt::ItemIsDropEnabled
    | Qt::ItemIsUserCheckable
    | Qt::ItemIsEnabled);
}
和KItemGroup.h #包括“KItemGroup.h”

每当我将第一个WTreeWifget中的一个项目放在第二个WTreeWifget的一个组中时,它都会工作,但当我将一个组移动到顶部QTreeWidget时,我会丢失所有的子项

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

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

我认为问题在于qabstractemmodel(在QTreeWidget中用于内部编码拖动的数据)方法(即它只编码行+列,而不编码父项)

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

我看到的唯一解决方案是重新实现dropevent,但你不必销毁这些项目。 使用

获取拖动的项目

放下它

我已经检查过孩子们是否能正确移动。(请参阅)

我就是这样解决的: 当您拖放时,At会创建一个新对象,该对象与您的对象不同,具有相同的文本值,但它是另一个对象,您的对象会被删除,但内存不会被释放

首先要做的是重写removeChild,因为它基于索引而不是地址,所以它不能很好地与我们后面要做的工作配合。()

然后我们需要做的是覆盖QTreeWidget的dropEvent

  • 获取所有应拖动但不是Qt的选定项
  • 允许Qt执行其下降操作
  • 查找目标上可能包含Qt创建的新对象的项目。这可以通过itemAt(事件->位置)完成
  • 在这些项的子项中查找哪些项是被删除的项:这可以通过动态_强制转换来完成,因为Qt创建的项是ATreeWidgetItems,而我们的项继承自该类
  • 获取它的索引
  • 删除“寄生虫”项,然后将其删除
  • 在寄生虫的索引处插入所选项目
  • 我们需要覆盖removeChild,因为我们正在手动删除子项(所选项),而Qt正在删除它应该删除的项(也是所选项)(但它没有)。因此,如果检查Qt代码,您将看到它基于索引,这是不安全的,而基于其地址删除项则更安全。 稍后我会在这里发布我的代码,我忘了提交;)


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

    嗨,对不起,我以前没打电话。我没有收到电子邮件通知!我实际上找到了解决方案,它和你的差不多:)我在下面给出了我的完整解决方案,这样其他人就可以看到;)您可以使QT忽略该事件。并将父对象与其他项目一起带走。似乎更简单。
    #include "KItem.h"
    
    KItem::KItem(QTreeWidget* p):KAbstractItem(p){
     setFlags(Qt::ItemIsSelectable 
      | Qt::ItemIsEditable 
      | Qt::ItemIsDragEnabled
      | Qt::ItemIsUserCheckable
      | Qt::ItemIsEnabled);
    }
    
    #ifndef _KIG_H_
    #define _KIG_H_
    
    #include "KAbstractItem.h"
    
    class KItemGroup : public KAbstractItem{
     Q_OBJECT
    public:
     KItemGroup(QTreeWidget* p);
    };
    
    #endif
    
    KItemGroup::KItemGroup(QTreeWidget* p):KAbstractItem(p){
     setFlags(Qt::ItemIsSelectable 
        | Qt::ItemIsEditable 
        | Qt::ItemIsDragEnabled
        | Qt::ItemIsDropEnabled
        | Qt::ItemIsUserCheckable
        | Qt::ItemIsEnabled);
    }