最近在做项目时,需要实现一个功能:
在一个QTreeWidget中,随意移动父节点或子节点的位置,但父节点和子节点不能互调。
用图来举例的话,大概是这个样子:
父节点[114514,114517]可以用鼠标拖拽。
比如将114514拖拽到114516后,那么114514就跑到了114516后面。
然后针对子节点[191981,191983]:
可以像父节点一样调换位置,也可以拖拽到其他父节点下面,成为其他父节点的子节点。
但父节点无法成为子节点,子节点也无法成为父节点。
本人首先学习了一下QDrag,然后没学懂,
于是就自己重写QTreeWidget的MousePressEvent,MouseMoveEvent以及MouseReleaseEvent来实现了。
大概的思路就是:
①在MousePressEvent中获取要拖拽的项目,记为pSource;
②在MouseMoveEvent中显示一个Label,用来更加显性的表示拖拽;
③在MouseReleaseEvent中获取拖拽到的项目,记为pTarget,然后将pSource插入到pTarget周围。
代码如下:
class DragTreeWidget : public QTreeWidget { Q_OBJECT public: DragTreeWidget(QWidget* parent = nullptr); private: //初始化函数 void initTreeWidget(); void mousePressEvent(QMouseEvent* ev) override; void mouseMoveEvent(QMouseEvent* ev) override; void mouseReleaseEvent(QMouseEvent* ev) override; private: //用来显示label,显性表示拖拽 QLabel label; //表示被拖拽的item QTreeWidgetItem* pSource; //表示被拖拽的item的父节点 QTreeWidgetItem* pParent; //表示被拖拽的item在父节点中的索引 int originIndex; //用于判断在mouseMoveEvent中是否已经移除了组件 bool isJudged; };
头文件,没什么好说的。
void DragTreeWidget::initTreeWidget() { for(int i=0;i<10;i++){ QTreeWidgetItem* pTopItem = new QTreeWidgetItem(this); pTopItem->setText(0,QString::number(114514+i)); addTopLevelItem(pTopItem); } for(int i=0;i<10;i++){ QTreeWidgetItem* pChildItem = new QTreeWidgetItem(topLevelItem(0)); pChildItem->setText(0,QString::number(191981+i)); topLevelItem(0)->addChild(pChildItem); } }
用来插入一些item用来进行实验。
DragTreeWidget::DragTreeWidget(QWidget *parent) :QTreeWidget(parent), label(this), pSource(nullptr) { initTreeWidget(); setHeaderHidden(true); label.resize(100,30); label.setText(""); label.hide(); }
类构造函数,隐藏了QTreeWidget的头部,设置label大小并隐藏label。
void DragTreeWidget::mousePressEvent(QMouseEvent *ev) { qDebug()<<"in mousePressEvent"<<endl; pSource = itemAt(ev->pos()); qDebug()<<pSource->text(0)<<endl; if(pSource->parent()){ qDebug()<<"source parent is "<<pSource->parent()->text(0)<<endl; } label.setText(pSource->text(0)); isJudged = false; QTreeWidget::mousePressEvent(ev); }
void DragTreeWidget::mouseMoveEvent(QMouseEvent *ev) { if(pSource==nullptr){ QTreeWidget::mouseMoveEvent(ev); return; } qDebug()<<"in mouseMoveEvent"<<endl; label.show(); label.move(ev->pos()); if(isJudged==false){ isJudged = true; if(pSource->parent()){ qDebug()<<"isSubItem"<<endl; pParent = pSource->parent(); originIndex = pParent->indexOfChild(pSource); pParent->takeChild(originIndex); } else{ qDebug()<<"isMainItem"<<endl; pParent = nullptr; takeTopLevelItem(indexOfTopLevelItem(pSource)); } qDebug()<<"source = "<<pSource->text(0)<<endl; } }
void DragTreeWidget::mouseReleaseEvent(QMouseEvent *ev) { qDebug()<<"in mouseReleaseEvent"<<endl; label.hide(); QTreeWidgetItem* pTarget = itemAt(ev->pos()); if(pTarget==nullptr){ if(pParent){ pParent->insertChild(originIndex,pSource); } else{ addTopLevelItem(pSource); } setCurrentItem(pSource); return; } // qDebug()<<"is child = "<<isChild<<endl; if(pTarget->parent()){ qDebug()<<"PTarget parent = "<<pTarget->parent()->text(0)<<endl; } //如果是父节点 if(pTarget->parent()==nullptr){ if(pParent){ pTarget->addChild(pSource); } else{ insertTopLevelItem(indexOfTopLevelItem(pTarget)+1,pSource); } } //如果是子节点 else{ if(pParent){ QTreeWidgetItem* parent = pTarget->parent(); parent->insertChild(parent->indexOfChild(pTarget)+1,pSource); } else{ } } setCurrentItem(pSource); }
mousePressEvent,mouseMoveEvent,mouseReleaseEvent不想写了,这玩意写了一天半,还是我太菜了。。。
以后也许会补全一下注释,让其更加容易理解。
整个源文件代码如下:
DragTreeWidget::DragTreeWidget(QWidget *parent) :QTreeWidget(parent), label(this), pSource(nullptr) { initTreeWidget(); setHeaderHidden(true); label.resize(100,30); label.setText(""); label.hide(); } void DragTreeWidget::initTreeWidget() { for(int i=0;i<10;i++){ QTreeWidgetItem* pTopItem = new QTreeWidgetItem(this); pTopItem->setText(0,QString::number(114514+i)); addTopLevelItem(pTopItem); } for(int i=0;i<10;i++){ QTreeWidgetItem* pChildItem = new QTreeWidgetItem(topLevelItem(0)); pChildItem->setText(0,QString::number(191981+i)); topLevelItem(0)->addChild(pChildItem); } } void DragTreeWidget::mousePressEvent(QMouseEvent *ev) { qDebug()<<"in mousePressEvent"<<endl; pSource = itemAt(ev->pos()); qDebug()<<pSource->text(0)<<endl; if(pSource->parent()){ qDebug()<<"source parent is "<<pSource->parent()->text(0)<<endl; } label.setText(pSource->text(0)); isJudged = false; QTreeWidget::mousePressEvent(ev); } void DragTreeWidget::mouseMoveEvent(QMouseEvent *ev) { if(pSource==nullptr){ QTreeWidget::mouseMoveEvent(ev); return; } qDebug()<<"in mouseMoveEvent"<<endl; label.show(); label.move(ev->pos()); if(isJudged==false){ isJudged = true; if(pSource->parent()){ qDebug()<<"isSubItem"<<endl; pParent = pSource->parent(); originIndex = pParent->indexOfChild(pSource); pParent->takeChild(originIndex); } else{ qDebug()<<"isMainItem"<<endl; pParent = nullptr; takeTopLevelItem(indexOfTopLevelItem(pSource)); } qDebug()<<"source = "<<pSource->text(0)<<endl; } } void DragTreeWidget::mouseReleaseEvent(QMouseEvent *ev) { qDebug()<<"in mouseReleaseEvent"<<endl; label.hide(); QTreeWidgetItem* pTarget = itemAt(ev->pos()); if(pTarget==nullptr){ if(pParent){ pParent->insertChild(originIndex,pSource); } else{ addTopLevelItem(pSource); } setCurrentItem(pSource); return; } // qDebug()<<"is child = "<<isChild<<endl; if(pTarget->parent()){ qDebug()<<"PTarget parent = "<<pTarget->parent()->text(0)<<endl; } //如果是父节点 if(pTarget->parent()==nullptr){ if(pParent){ pTarget->addChild(pSource); } else{ insertTopLevelItem(indexOfTopLevelItem(pTarget)+1,pSource); } } //如果是子节点 else{ if(pParent){ QTreeWidgetItem* parent = pTarget->parent(); parent->insertChild(parent->indexOfChild(pTarget)+1,pSource); } else{ } } setCurrentItem(pSource); }