1. 程式人生 > 其它 >QTreeWidget自實現拖拽移動內容(不使用QDrag)

QTreeWidget自實現拖拽移動內容(不使用QDrag)

最近在做專案時,需要實現一個功能:

在一個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);
}