QTreeWidget自實現拖拽移動內容(不使用QDrag)
阿新 • • 發佈:2021-07-20
最近在做專案時,需要實現一個功能:
在一個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); }