精华内容
下载资源
问答
  • Qt功能点之两个QTreeWidget相互拖动节点Qt功能点之两个QTreeWidget相互拖动节点Qt功能点之两个QTreeWidget相互拖动节点Qt功能点之两个QTreeWidget相互拖动节点Qt功能点之两个QTreeWidget相互拖动节点Qt功能点之两个...
  • QTreeWidget实现节点拖拽

    千次阅读 热门讨论 2019-04-29 11:54:31
    刚进公司没多久,老大就让做一个实现拖放的小插件,要求可拖拽,可缩放。从网上查了很多资料,也看了别人写的demo,总算摸索出一些门道,下面分享给大家,如有疑问,可评论,大家一起学习! 效果 核心代码 ...

    前言

    刚进公司没多久,老大就让做一个实现拖放的小插件,要求可拖拽,可缩放。从网上查了很多资料,也看了别人写的demo,总算摸索出一些门道,界面布局有些丑,希望大家不要介意,下面分享给大家,如有疑问,可评论,大家一起学习!

    效果

    在这里插入图片描述

    核心代码

    QCTreeWidget.cpp

    // 左侧项目树
    QCTreeWidget::QCTreeWidget(const QString& text, QWidget *parent)
    : QTreeWidget(parent)
    {
        this->setSelectionMode(QAbstractItemView::ExtendedSelection);
        this->setDragEnabled(true);
        this->setAcceptDrops(true);
        this->setDefaultDropAction(Qt::MoveAction);
        //this->setDragDropMode(QAbstractItemView::DragDrop);
        this->setDragDropMode(QAbstractItemView::InternalMove);
    }
    
    void QCTreeWidget::mousePressEvent(QMouseEvent *e)
    {
        QTreeWidgetItem *item = currentItem();
        if (item == NULL)
            return;
    
        QString pValue = QString::number(int((void*)item));
        QByteArray itemData;
        itemData = QVariant(pValue).toByteArray();
    
        QMimeData *mimeData = new QMimeData;
        mimeData->setData("application/x-qabstractitemmodeldatalist", itemData);
    
        QDrag *drag = new QDrag(this);
        drag->setMimeData(mimeData);
    
        hide();
    
        Qt::DropAction dropAction = drag->exec(Qt::CopyAction | Qt::MoveAction);
    
        if (dropAction == Qt::MoveAction)
            close();
        else
            show();
    }
    
    void QCTreeWidget::dragEnterEvent(QDragEnterEvent *event)
    {
        QWidget *source =  qobject_cast<QCTreeWidget *>(event->source());
        if (source /*&& source != this*/)
        {
            event->setDropAction(Qt::MoveAction);
            /*event->setDropAction(Qt::MoveAction);  */
            event->accept();
        }
    }
    
    void QCTreeWidget::dragMoveEvent(QDragMoveEvent *event)
    {
        QWidget *source =  qobject_cast<QCTreeWidget *>(event->source());
        if (source /*&& source != this*/)
        {
            event->setDropAction(Qt::MoveAction);
            event->accept();
        }
    }
    
    void QCTreeWidget::dropEvent(QDropEvent *event)
    {
        QCTreeWidget *source =  qobject_cast<QCTreeWidget *>(event->source());
        if (source /*&& source != this*/)
        {
            QCTreeWidget *source = qobject_cast<QCTreeWidget *>(event->source());
            if(source)
            {
                QTreeWidgetItem *item = this->itemAt(event->pos()); //当前位置的item
                if( item == nullptr)   //如果放下的位置没有item,则退出,没有这句话死机!
                    return;
    			//如果“放下位置的item是顶层item,且原来的是顶层”或者“放下的不是顶层,且原来也不是顶层”
                if( -1 == this->indexOfTopLevelItem(item) && (-1 == this->indexOfTopLevelItem(currentItem())) ||
                        -1 != this->indexOfTopLevelItem(item) && (-1 != this->indexOfTopLevelItem(currentItem())))
     
                {
                    qDebug()<< QStringLiteral("放下的文本是: ")<<event->mimeData()->text();
                    item->setText(currentColumn(),event->mimeData()->text());
                    event->setDropAction(Qt::MoveAction);
                    event->accept();
                }
            }
        }
    }
    
    void QCTreeWidget::startDrag(Qt::DropActions /*supportedActions*/)
    {
        QMimeData *mimeData = new QMimeData;
        mimeData->setText("fasfas");
        QDrag *drag = new QDrag((QWidget*)(this));
        drag->setMimeData(mimeData);
        drag->exec(Qt::MoveAction);//注意这里一定要是MoveAction
    }
    
    void QCTreeWidget::mouseMoveEvent(QMouseEvent *e)
    {
        if(e->buttons() & Qt::LeftButton)
        {
            //int distance = (e->pos() - _startPos).manhattanLength();
            int distance = e->pos().manhattanLength();
            if(distance >= QApplication::startDragDistance())   //当拖动距离大于一个推荐抖动距离时,表示同意已经拖动操作了
                performDrag();
        }
        QTreeWidget::mouseMoveEvent(e);
    }
    
    void QCTreeWidget::performDrag()
    {
        QTreeWidgetItem *item = currentItem();
        int column = currentColumn();
        if(item)  //必须是非顶层item才可以移动数据
    // if(item)
        {
            QMimeData *mineData = new QMimeData;
            if(column != 4)   //只有第四列才可以移动数据
                return;
            mineData->setText(item->text(column));
            qDebug()<<item->text(column);
    
            QDrag *drag = new QDrag(this);
            drag->setMimeData(mineData);
            drag->exec(Qt::MoveAction);
        }
    }
    
    

    DragTreeWidget.cpp

    DragTreeWidget::DragTreeWidget(QWidget *parent) :
        QWidget(parent),
        ui(new Ui::DragTreeWidget)
    {
        ui->setupUi(this);
    
        // 开启鼠标跟踪
        setMouseTracking(true);
    
        ui->treeWidget->setColumnCount(1); //设置列数
        ui->treeWidget->setColumnWidth(0, 200); //设置列宽
        ui->treeWidget->setHeaderHidden(true); //隐藏标题栏
    
        //启用拖放
        ui->treeWidget->setDragEnabled(true);
        //设置拖放
        ui->treeWidget->setAcceptDrops(true);
    
        //设置显示将要被放置的位置
        //ui->treeWidget->setDropIndicatorShown(true);
    
        //设置拖放模式为移动项目,否则为复制项目
        ui->treeWidget->setDragDropMode(QAbstractItemView::InternalMove);
    
        //设置item进入编辑的方式
        ui->treeWidget->setEditTriggers(QAbstractItemView::SelectedClicked);
        init();// 初始化项目树
        //createUI();// 初始化文本文字
        QString str;
        m_pCustomDragLabel = new CustomDragLabel(str, this);
    
        //connect(m_pCustomDragLabel, SIGNAL(wantToGetPoint()), this, SLOT(receiverSIGNAL()));
        //connect(this, SIGNAL(sendPoint(QPoint)), m_pCustomDragLabel, SLOT(receiverData(QPoint)));
    
    
    }
    
    DragTreeWidget::~DragTreeWidget()
    {
        delete ui;
    }
    
    void DragTreeWidget::init()
    {
        QTreeWidgetItem *imageItem1 = new QTreeWidgetItem(ui->treeWidget,QStringList(QString("图像1")));
        imageItem1->setIcon(0,QIcon("xxx.png"));
        QTreeWidgetItem *imageItem1_1 = new QTreeWidgetItem(imageItem1,QStringList(QString("Band1"))); //子节点1
        imageItem1->addChild(imageItem1_1); //添加子节点
    
        QTreeWidgetItem *imageItem2 = new QTreeWidgetItem(ui->treeWidget,QStringList(QString("图像2")));
        QTreeWidgetItem *imageItem2_1 = new QTreeWidgetItem(imageItem2,QStringList(QString("Band1"))); //子节点1
        QTreeWidgetItem *imageItem2_2 = new QTreeWidgetItem(imageItem2,QStringList(QString("Band2"))); //子节点2
        imageItem2->addChild(imageItem2_1);  //添加子节点
        imageItem2->addChild(imageItem2_2);
    
        ui->treeWidget->expandAll(); //结点全部展开
    }
    
    void DragTreeWidget::createUI()
    {
        QTextEdit *edit = new QTextEdit;
        edit->setText(QObject::tr("中国欢迎您!\n 地球欢迎您!"));
        ui->verticalLayout->addWidget(edit);
        //ui->addWidget(edit);
    }
    
    void DragTreeWidget::dragEnterEvent(QDragEnterEvent *e)
    {
    	// 如果要配置mimeData层级树的类型,必须是“application/x-qabstractitemmodeldatalist”,具体原因不清楚
        if (e->mimeData()->hasText() || e->mimeData()->hasFormat("application/x-qabstractitemmodeldatalist"))
        {
            QByteArray data = e->mimeData()->data("application/x-qabstractitemmodeldatalist");
            QTreeWidgetItem *item = (QTreeWidgetItem*)((void*)QVariant(data).toInt());
    
            m_nPos = e->pos();
            QTreeWidgetItem *pItem = ui->treeWidget->itemAt(m_nPos);
    
            if(children().contains(e->source()))
            {
                e->setDropAction(Qt::CopyAction);
                e->accept();
            }
            else
                e->acceptProposedAction();
        }
    }
    
    void DragTreeWidget::dragMoveEvent(QDragMoveEvent *e)
    {
        if (e->mimeData()->hasText() || e->mimeData()->hasFormat("application/x-qabstractitemmodeldatalist"))
        {
            if(children().contains(e->source()))
            {
                e->setDropAction(Qt::CopyAction);
                e->accept();
            }
            else
                e->acceptProposedAction();
        }
    }
    
    void DragTreeWidget::dropEvent(QDropEvent *e)
    {
        if (e->mimeData()->hasFormat("application/x-qabstractitemmodeldatalist"))
        {// 配置mimeData类型的层级树
            QByteArray data = e->mimeData()->data("application/x-qabstractitemmodeldatalist");
    
            QString strr;
            QByteArray strList;
            for (int i = 0; i < data.size(); i++)
            {
                if (data[i] != '\0')
                {
                    strList.push_back(data[i]);
                }
            }
            strr = strList;
    		
    		// 创建自定义Label
            CustomDragLabel *label = new CustomDragLabel(strr, this);
    		label->setStyleSheet("background-color: rgb(0,255,0);color: rgb(255,255,255);");
            label->move(e->pos());
            label->setAutoFillBackground(true);
            ui->verticalLayout->addWidget(label);
            label->show();
    
            if (children().contains(e->source()))
            {
                e->setDropAction(Qt::CopyAction);
                e->accept();
            }
            else
            {
                e->acceptProposedAction();
            }
        }
        else if (e->mimeData()->hasText())
        {// 配置mimeData类型的文本
            QStringList strList = e->mimeData()->text().split(QRegExp("\\s+"),QString::SkipEmptyParts);
            QPoint pos = e->pos();
    
            foreach(QString str, strList)
            {
                DragLabel *dragLabel = new DragLabel(str,this);
                dragLabel->move(pos);
                dragLabel->show();
                pos += QPoint(dragLabel->width(),0);
            }
            if (children().contains(e->source()))
            {
                e->setDropAction(Qt::MoveAction);
                e->accept();
            }
            else
            {
                e->acceptProposedAction();
            }
        }
        else
        {
            e->ignore();
        }
    }
    
    void DragTreeWidget::receiverSIGNAL()
    {
        QPoint point = mapFromGlobal(QCursor::pos());
        //qDebug()<<point;  不要直接把mapFromGlobal(QCursor::pos())传进去,不然有BUG
        emit sendPoint(point);
    }
    
    

    CustomDragLabel.cpp

    CustomDragLabel::CustomDragLabel(const QString &str, QWidget* parent)
        : QLabel(str, parent)
    {
    	m_dragFlag = false;
    	m_leftFlag = false;
    	m_rightFlag = false;
    	this->setMouseTracking(true);
    
    	setMinimumSize(50, 50);
    	setMaximumSize(800, 800);
    	
    	// 创建可拖拽、可缩放窗体
        DragProxy *m_pDragProxy = new DragProxy(this);
        m_pDragProxy->SetBorderWidth(8,8,8,8);
    }
    
    CustomDragLabel::~CustomDragLabel()
    {
    
    }
    

    DragProxy.cpp

    // 自定义可拖拽、可缩放窗体
    DragProxy::DragProxy(QWidget *parent)
        : QObject((QObject*)parent)
    {
        m_proxyWidget = parent;
        m_top = m_right = m_bottom = m_left = 0;
    
        m_proxyWidget->setMouseTracking(true);
        m_proxyWidget->installEventFilter(this); // 代理窗体事件
    
        m_mousePressed = false;
        m_regionPressed = Unknown;
    
        m_cursorTimerId = 0;
    }
    
    DragProxy::~DragProxy()
    {
    }
    
    void DragProxy::SetBorderWidth(int top, int right, int bottom, int left)
    {
        m_top = top;
        m_right = right;
        m_bottom = bottom;
        m_left = left;
    
        MakeRegions();
    }
    
    void DragProxy::UpdateGeometry(int x, int y, int w, int h)
    {
        int minWidth = m_proxyWidget->minimumWidth();
        int minHeight = m_proxyWidget->minimumHeight();
        int maxWidth = m_proxyWidget->maximumWidth();
        int maxHeight = m_proxyWidget->maximumHeight();
    
        if (w < minWidth || w > maxWidth || h < minHeight || h > maxHeight)
        {
            return;
        }
    
        m_proxyWidget->setGeometry(x, y, w, h);
    }
    
    bool DragProxy::eventFilter(QObject* obj, QEvent* event)
    {
        QEvent::Type eventType = event->type();
        if (eventType == QEvent::MouseMove)
        {
            QMouseEvent* mouseEvent = (QMouseEvent*)event;
            QPoint curPosLocal = mouseEvent->pos();
            DragProxy::WidgetRegion regionType = HitTest(curPosLocal);
    
            QPoint curPosGlobal = m_proxyWidget->mapToGlobal(curPosLocal);
    
            if (!m_mousePressed)    // 鼠标未按下
            {
                switch (regionType)
                {
                case Top:
                case Bottom:
                    m_proxyWidget->setCursor(Qt::SizeVerCursor);
                    break;
                case TopRight:
                case LeftBottom:
                    m_proxyWidget->setCursor(Qt::SizeBDiagCursor);
                    break;
                case Right:
                case Left:
                    m_proxyWidget->setCursor(Qt::SizeHorCursor);
                    break;
                case RightBottom:
                case LeftTop:
                    m_proxyWidget->setCursor(Qt::SizeFDiagCursor);
                    break;
                default:
                    m_proxyWidget->setCursor(Qt::ArrowCursor);
                    break;
                }
    
                StartCursorTimer();
            }
            else    // 鼠标已按下
            {
                QRect geo = m_proxyWidget->geometry();
    
                if (m_regionPressed == Inner)
                {
                    m_proxyWidget->move(m_originGeo.topLeft() + curPosGlobal - m_originPosGlobal);
                }
                else if (m_regionPressed == Top)
                {
                    int dY = curPosGlobal.y() - m_originPosGlobal.y();
                    UpdateGeometry(m_originGeo.x(), m_originGeo.y() + dY, m_originGeo.width(), m_originGeo.height() - dY);
                }
                else if (m_regionPressed == TopRight)
                {
                    QPoint dXY = curPosGlobal - m_originPosGlobal;
                    UpdateGeometry(m_originGeo.x(), m_originGeo.y() + dXY.y(), m_originGeo.width() + dXY.x(), m_originGeo.height() - dXY.y());
                }
                else if (m_regionPressed == Right)
                {
                    int dX = curPosGlobal.x() - m_originPosGlobal.x();
                    UpdateGeometry(m_originGeo.x(), m_originGeo.y(), m_originGeo.width() + dX, m_originGeo.height());
                }
                else if (m_regionPressed == RightBottom)
                {
                    QPoint dXY = curPosGlobal - m_originPosGlobal;
                    UpdateGeometry(m_originGeo.x(), m_originGeo.y(), m_originGeo.width() + dXY.x(), m_originGeo.height() + dXY.y());
                }
                else if (m_regionPressed == Bottom)
                {
                    int dY = curPosGlobal.y() - m_originPosGlobal.y();
                    UpdateGeometry(m_originGeo.x(), m_originGeo.y(), m_originGeo.width(), m_originGeo.height() + dY);
                }
                else if (m_regionPressed == LeftBottom)
                {
                    QPoint dXY = curPosGlobal - m_originPosGlobal;
                    UpdateGeometry(m_originGeo.x() + dXY.x(), m_originGeo.y(), m_originGeo.width() - dXY.x(), m_originGeo.height() + dXY.y());
                }
                else if (m_regionPressed == Left)
                {
                    int dX = curPosGlobal.x() - m_originPosGlobal.x();
                    UpdateGeometry(m_originGeo.x() + dX, m_originGeo.y(), m_originGeo.width() - dX, m_originGeo.height());
                }
                else if (m_regionPressed == LeftTop)
                {
                    QPoint dXY = curPosGlobal - m_originPosGlobal;
                    UpdateGeometry(m_originGeo.x() + dXY.x(), m_originGeo.y() + dXY.y(), m_originGeo.width() - dXY.x(), m_originGeo.height() - dXY.y());
                }
            }
        }
        else if (eventType == QEvent::MouseButtonPress)
        {
            QMouseEvent* mouseEvent = (QMouseEvent*)event;
            if (mouseEvent->button() == Qt::LeftButton)
            {
                m_mousePressed = true;
    
                QPoint curPos = mouseEvent->pos();
                m_regionPressed = HitTest(curPos);
    
                m_originPosGlobal = m_proxyWidget->mapToGlobal(curPos);
                m_originGeo = m_proxyWidget->geometry();
    
                StopCursorTimer();
            }
        }
        else if (eventType == QEvent::MouseButtonRelease)
        {
            m_mousePressed = false;
            m_regionPressed = Unknown;
    
            m_proxyWidget->setCursor(Qt::ArrowCursor);
        }
        else if (eventType == QEvent::Resize)
        {
            MakeRegions();
        }
        else if (eventType == QEvent::Leave)
        {
            m_proxyWidget->setCursor(Qt::ArrowCursor);
            StopCursorTimer();
        }
        else if (eventType == QEvent::Timer)
        {
            QTimerEvent* timerEvent = (QTimerEvent*)event;
            if (timerEvent->timerId() == m_cursorTimerId)
            {
                if (m_regions[Inner].contains(m_proxyWidget->mapFromGlobal(QCursor::pos())))
                {
                    m_proxyWidget->setCursor(Qt::ArrowCursor);
                    StopCursorTimer();
                }
            }
        }
    
        return QObject::eventFilter(obj, event);
    }
    
    void DragProxy::StartCursorTimer()
    {
        StopCursorTimer();
        m_cursorTimerId = m_proxyWidget->startTimer(50);
    }
    
    void DragProxy::StopCursorTimer()
    {
        if (m_cursorTimerId != 0)
        {
            m_proxyWidget->killTimer(m_cursorTimerId);
            m_cursorTimerId = 0;
        }
    }
    
    void DragProxy::MakeRegions()
    {
        int width = m_proxyWidget->width();
        int height = m_proxyWidget->height();
    
        m_regions[Top]          = QRect(m_left, 0, width - m_left - m_right, m_top);
        m_regions[TopRight]     = QRect(width - m_right, 0, m_right, m_top);
        m_regions[Right]        = QRect(width - m_right, m_top, m_right, height - m_top - m_bottom);
        m_regions[RightBottom]  = QRect(width - m_right, height - m_bottom, m_right, m_bottom);
        m_regions[Bottom]       = QRect(m_left, height - m_bottom, width - m_left - m_right, m_bottom);
        m_regions[LeftBottom]   = QRect(0, height - m_bottom, m_left, m_bottom);
        m_regions[Left]         = QRect(0, m_top, m_left, height - m_top - m_bottom);
        m_regions[LeftTop]      = QRect(0, 0, m_left, m_top);
        m_regions[Inner]        = QRect(m_left, m_top, width - m_left - m_right, height - m_top - m_bottom);
    }
    
    DragProxy::WidgetRegion DragProxy::HitTest(const QPoint& pos)
    {
        for (int i = 0; i < 9; i++)
        {
            const QRect rect = m_regions[i];
            if (rect.contains(pos))
            {
                return DragProxy::WidgetRegion(i);
            }
        }
    
        return Unknown;
    }
    
    展开全文
  • Qt之 QTreeWidget:1 拖拽项目 ​ QTreeWidget拖拽实现,比较简单,但过程是绕了点路的,按照常规的方法:子类化QTreeWidget、重写 Drag 和 Drop的相关事件、利用QMimeData,QDrag类来实现,功能虽然实现了,但是...

    Qt之 QTreeWidget:1 拖拽项目

    ​ QTreeWidget 的拖拽实现,比较简单,但过程是绕了点路的,按照常规的方法:子类化QTreeWidget、重写 Drag 和 Drop的相关事件、利用QMimeData,QDrag类来实现,功能虽然实现了,但是关闭程序是,有可能会出现异常,类似 指针被二次析构了一样。偶发性的错误,挺让我头疼。

    ​ 牢骚过后,上干货。

    一、官档

    ​ 【 Model/View Programming 】主题中有这么一段,并试着翻译成中文,便于理解。

    在便捷类中使用 拖放 功能

    QListWidget、QTableWidget和QTreeWidget 中 项目 默认配置了一组不同的标志。例如,每个QListWidgetItem或QTreeWidgetItem最初都是 enabled 启用的、checkable 可检查的、selectable可选择的,并且可以用作拖放源;每个QTableWidgetItem也可以编辑并用作拖放操作的目标。

    通常需要在视图本身中设置相关属性启动对拖放的内置支持:

    • 设置dragEnabled属性为true,启用项拖动功能
    • 设置 viewport() 的acceptDrops属性设置为true,允许用户在视图中放置内部或外部的项
    • 设置视图的showDropIndicator属性,向用户显示当前正在拖动的项以及放置的位置。
    • 设置视图的 dragDropMode(QAbstractItemView::InternalMove),在视图中移动项目,

    二、测试

    上述内容还是比较容易理解的,那就看看实际效果呗。

    #include <QtWidgets>
    #include "../../DebugTools/DebugTool.h"
    void init(QTreeWidget &w){
      w.setHeaderLabels ({"节点","内容"});
      QList<QTreeWidgetItem *> list;
    
      // 3 行 2列,每行2个子节点
      for (int i = 0; i < 3; ++i) {
        QTreeWidgetItem *item = new QTreeWidgetItem(&w);
        item->setFlags (Qt::ItemIsEditable | item->flags ());
        cout << item->flags ();
        item->setExpanded (true); // 只有设置了父控件,才能展开
        list << item;
        item->setText (0,QString("父节点%1").arg (i));
        item->setText (1,item->text (0));
    
        for (int j = 0; j < 2; ++j) {
          QTreeWidgetItem *child = new QTreeWidgetItem(item);
          child->setFlags (Qt::ItemIsEditable | item->flags ());
          child->setText (0,QString("子节点%1-%2").arg (i).arg(j));
          child->setText (1,child->text (0));
        }
      }
      w.addTopLevelItems (list);
      w.resize (300,300);
      w.resizeColumnToContents (1);
      w.header ()->setSectionsClickable (false);
      w.setEditTriggers (QTreeWidget::DoubleClicked );
    }
    
    void setDragAndDrop(QTreeWidget &w){
      w.setDragEnabled (true);              // 启用拖动
      w.viewport ()->setAcceptDrops (true); // viewport 接受放下动作,默认是复制操作
      w.showDropIndicator ();               // 设置放下指示
      w.setDragDropMode (QTreeWidget::InternalMove);// 内部 移动
    }
    
    void setSelectionMode(QTreeWidget &w){
      w.setSelectionBehavior (QTreeWidget::SelectRows);     // 选择行
      w.setSelectionMode (QTreeWidget::ContiguousSelection);// 连续选择
    }
    
    int main(int argc, char *argv[])
    {
      QApplication a(argc, argv);
      QTreeWidget w;
      // 初始化Tree
      init (w);
      // 设置Tree的拖放
      setDragAndDrop(w);
      // 设置Tree的选定模式和行为
      setSelectionMode (w);
      w.show ();
      return a.exec();
    }
    
    展开全文
  • Qt读写Xml文件;QTreeWidget加载显示Xml文件内容;QTreeWidget项导出保存为Xml;QTreeWidget项实现可拖动、编辑、创建、删除等
  • QTreeWidget实现多节点拖拽

    千次阅读 2020-04-18 17:18:02
    QTreeWidget实现多节点拖拽 1.重载QTreeWidget这个类,在构造函数设置多选节点: //按 ctrl 或 shift 多选 this->setSelectionMode(QAbstractItemView::ExtendedSelection); //设置可拖拽性质 this->...

    QTreeWidget实现多节点拖拽

    1.重载QTreeWidget这个类,在构造函数设置多选节点:

    //按 ctrl 或 shift 多选
    this->setSelectionMode(QAbstractItemView::ExtendedSelection);
    //设置可拖拽性质
    this->setDefaultDropAction(Qt::MoveAction);
    this->setDragDropMode(QAbstractItemView::DragDrop);
    

    如果需要在实现多节点拖拽的基础上处理业务,就要对下面几个拖拽函数进行重载。

    2.声明私有变量m_dragItemVec,用来存储拖拽的节点

    std::vector<QTreeWidgetItem*> m_dragItemVec;
    

    3.重写拖拽函数

      		virtual void dragEnterEvent(QDragEnterEvent *ev);
     		virtual	void dragMoveEvent(QDragMoveEvent * ev);
     		virtual void dropEvent(QDropEvent *ev);
    

    3.1:对于dragEnterEvent,将选中的items存进私有变量m_dragItemVec

    void dragEnterEvent(QDragEnterEvent *ev)
    {
    	ev->setDropAction(Qt::MoveAction);
    	QList<QTreeWidgetItem*> selectedItem = selectedItems();
    	m_dragItemVec.clear();
    	for (int i = 0; i < selectedItem.size(); i++)
    	{
    		if (selectedItem[i] && selectedItem[i]->parent())
    		{
    			m_dragItemVec.push_back(selectedItem[i]);
    		}
    	}
    	if (m_dragItemVec.size() > 0)
    	{
    		ev->acceptProposedAction();
    		QTreeWidget::dragEnterEvent(ev);
    		return;
    	}
    	ev->ignore();
    	QTreeWidget::dragEnterEvent(ev);
    }
    

    3.2:对于dragMoveEvent,在这里设置可拖拽区域

    void dragMoveEvent(QDragMoveEvent * ev)
    {
    	ev->setDropAction(Qt::MoveAction);
    	
    	QTreeWidgetItem* itemOver = itemAt(ev->pos());
    	//设置可拖拽区域
    	if (itemOver != NULL && itemOver->parent() != NULL)
    	{
    			ev->acceptProposedAction();
    			QTreeWidget::dragMoveEvent(ev);
    			return;
    		}
    	}
    	
    	ev->ignore();
    	QTreeWidget::dragMoveEvent(ev);
    }
    

    3.3:对于dropEvent,在这里插入拖拽节点

    void dropEvent(QDropEvent *ev)
    {
    	QTreeWidgetItem* itemOver = itemAt(ev->pos());
    	if (itemOver != NULL && itemOver->parent())
    	{
    		//在此可以对m_dragItemVec做你想做的事
    		
    		QTreeWidget::dropEvent(ev);
    		setCurrentItem(itemOver); // 设置为当前选中
    		itemOver->setExpanded(true);
    		return;	
    	}
    	ev->ignore();
    	//QTreeWidget::dropEvent(ev);//如果不符合拖拽要求,这句可以注释掉
    }
    
    展开全文
  • QTreeWidget 自身节点拖拽

    千次阅读 2020-08-28 15:41:30
    通过一个例子学习 QTreeWidget 节点的拖拽功能。本示例仅实现树形结构的自我拖拽,用来更改上下级关系或者调整节点顺序。 子类化 QTreeWidget 概述 通过子类化 QTreeWidget 重新实现相关事件,以实现自定义功能。 ...

    前言

    通过一个例子学习 QTreeWidget 节点的拖拽功能。本示例仅实现树形结构的自我拖拽,用来更改上下级关系或者调整节点顺序。
    在这里插入图片描述

    子类化 QTreeWidget

    1. 概述
      通过子类化 QTreeWidget 重新实现相关事件,以实现自定义功能。
    2. 头文件
    #ifndef MYTREEWIDGET_H
    #define MYTREEWIDGET_H
    #include <QTreeWidget>
    
    class MyTreeWidget : public QTreeWidget
    {
        Q_OBJECT
    public:
        explicit MyTreeWidget( QWidget * parent = nullptr);
    protected:
        //需要重新实现的事件
        void mousePressEvent(QMouseEvent *event);
        void mouseMoveEvent(QMouseEvent *event);
        void dragEnterEvent(QDragEnterEvent * event);
        void dropEvent(QDropEvent *event);
        void dragMoveEvent(QDragMoveEvent *event);
    private:
        QPoint startDragPoint;
    };
    
    #endif // MYTREEWIDGET_H
    
    1. 源码文件
    #include "mytreewidget.h"
    #include <QMouseEvent>
    #include <QApplication>
    #include "dragimage.h"
    #include "treeitemmimedata.h"
    #include <QDrag>
    #include "dragmodedialog.h"
    
    
    MyTreeWidget::MyTreeWidget(QWidget *parent):QTreeWidget(parent)
    {
        this->setSelectionMode(QAbstractItemView::SingleSelection);
        this->setDragEnabled(true);
        this->viewport()->setAcceptDrops(true);
        this->setDragDropMode(QAbstractItemView::InternalMove);
    }
    
    void MyTreeWidget::mousePressEvent(QMouseEvent *event)
    {
        if( event->button() == Qt::LeftButton )
        {
            startDragPoint = event->pos();
        }
        QTreeWidget::mousePressEvent(event);
    }
    
    void MyTreeWidget::mouseMoveEvent(QMouseEvent *event)
    {
        if( event->buttons() & Qt::LeftButton)//判断左键按下
        {
            int distance = (event->pos()-startDragPoint ).manhattanLength();
            if( distance > QApplication::startDragDistance())
            {
                 QTreeWidgetItem * item = this->currentItem();
                 DragImage *dragimag = new DragImage;
                 dragimag->setShowText(item->text(0));
                 dragimag->setShowIcon(item->icon(0));
                 QPixmap pixmap = dragimag->grab();
                 TreeItemMimeData *mimedata = new TreeItemMimeData;
                 mimedata->SetDragData("ItemMimeData",item);
    
                 QDrag *drag = new QDrag(this);
                 drag->setMimeData(mimedata);
                 drag->setPixmap(pixmap);
                 drag->setHotSpot(QPoint(pixmap.width() / 2, pixmap.height() / 2));
                 if( drag->exec(Qt::MoveAction) == Qt::MoveAction)
                 {
                     delete  item;
                     item = nullptr;
                 }
            }
        }
        QTreeWidget::mouseMoveEvent(event);
    }
    
    void MyTreeWidget::dragEnterEvent(QDragEnterEvent *event)
    {
        if (event->mimeData()->hasFormat("ItemMimeData") &&  event->source() == this )
        {
            event->setDropAction(Qt::MoveAction);
            event->accept();
        }
        else
            event->ignore();
    }
    
    void MyTreeWidget::dropEvent(QDropEvent *event)
    {
        if(event->mimeData()->hasFormat("ItemMimeData") && event->source() == this )
        {
            const TreeItemMimeData *pMimeData = (const TreeItemMimeData *)(event->mimeData());
            const QTreeWidgetItem *item = pMimeData->DragItemData();
            QTreeWidgetItem *pItem = item->clone();
            QTreeWidgetItem *currentItem = this->itemAt(event->pos());
            bool canceldrag = false;
            if( currentItem == nullptr )
            {
                this->addTopLevelItem(pItem);
            }
            else
            {
                QTreeWidgetItem * currenParent = currentItem->parent();
                DragModeDialog *dlg = new DragModeDialog;
                dlg->setShowText(pItem->text(0),currentItem->text(0));
                dlg->setShowPixm(pItem->icon(0).pixmap(20,20));
                if( dlg->exec() == QDialog::Accepted)
                {
                    DragModeDialog::DragMode dragmode = dlg->selMode;
                    switch (dragmode)
                    {
                        case DragModeDialog::DragAsChild:
                            currentItem->addChild(pItem);
                            break;
                        case DragModeDialog::DragToUp:
                            currenParent == nullptr ? insertTopLevelItem(indexOfTopLevelItem(currentItem),pItem) : currenParent->insertChild(currenParent->indexOfChild(currentItem),pItem);
                            break;
                        case DragModeDialog::DragToDown:
                            currenParent == nullptr ? insertTopLevelItem(indexOfTopLevelItem(currentItem)+1,pItem) : currenParent->insertChild(currenParent->indexOfChild(currentItem)+1,pItem);
                            break;
                    }
                }
                else
                {
                    canceldrag = true;
                }
            }
            if( !canceldrag)
            {
                event->setDropAction(Qt::MoveAction);
                event->accept();
            }
            else
                event->ignore();
        }
        else
            event->ignore();
    
    }
    
    void MyTreeWidget::dragMoveEvent(QDragMoveEvent *event)
    {
        if (event->mimeData()->hasFormat("ItemMimeData") && event->source() == this )
        {
             const TreeItemMimeData *pMimeData = (const TreeItemMimeData *)(event->mimeData());
             const QTreeWidgetItem *item = pMimeData->DragItemData();
    
             QTreeWidgetItem *currentItem = this->itemAt(event->pos());
             bool isok = true;
             while(currentItem)
             {
                 if(currentItem == item)
                 {
                     isok = false;
                     break;
                 }
                 currentItem = currentItem->parent();
             }
             if( isok )
             {
                 event->setDropAction(Qt::CopyAction);
                 event->accept();
             }
             else
                 event->ignore();
        }
        else
            event->ignore();
    }
    
    

    子类化 QMimeData

    1. 概述
      通过子类化 QMimeData 实现自定义数据类型的传递。
    2. 头文件
    #ifndef TREEITEMMIMEDATA_H
    #define TREEITEMMIMEDATA_H
    #include <QMimeData>
    
    class QTreeWidgetItem;
    class TreeItemMimeData : public QMimeData
    {
        Q_OBJECT
    public:
        TreeItemMimeData():QMimeData(){};
        QStringList formats() const {return m_format ;}
        const QTreeWidgetItem * DragItemData() const { return  m_pDragItem;}
        void SetDragData(QString mimeType,QTreeWidgetItem * pItem);
    private:
        QStringList m_format;
        const QTreeWidgetItem * m_pDragItem;
    protected:
        QVariant retrieveData(const QString &mimetype, QVariant::Type preferredType) const ;
    };
    
    #endif // TREEITEMMIMEDATA_H
    
    1. 源码文件
    #include "treeitemmimedata.h"
    
    
    
    void TreeItemMimeData::SetDragData(QString mimeType, QTreeWidgetItem *pItem)
    {
        m_format << mimeType;
        m_pDragItem = pItem;
    }
    
    QVariant TreeItemMimeData::retrieveData(const QString &mimetype, QVariant::Type preferredType) const
    {
        if( mimetype == "ItemMimeData")
        {
            return m_pDragItem;
        }
        else
            return QMimeData::retrieveData(mimetype,preferredType);
    }
    
    

    拖拽过程图片显示

    1. 概述
      使用 QPushButton 可以同时显示图标和文字,设置边框样式后可以达到需要的效果。
    2. 头文件
    #ifndef DRAGIMAGE_H
    #define DRAGIMAGE_H
    
    #include <QWidget>
    
    namespace Ui {
    class DragImage;
    }
    
    class DragImage : public QWidget
    {
        Q_OBJECT
    
    public:
        explicit DragImage(QWidget *parent = nullptr);
        ~DragImage();
        void setShowText(QString text);//拖动时显示的文字
        void setShowIcon(QIcon pix);//拖动时显示的图标
    
    private:
        Ui::DragImage *ui;
    };
    
    #endif // DRAGIMAGE_H
    
    1. 源码文件
    #include "dragimage.h"
    #include "ui_dragimage.h"
    
    DragImage::DragImage(QWidget *parent) :
        QWidget(parent),
        ui(new Ui::DragImage)
    {
        ui->setupUi(this);
        this->setWindowFlags(Qt::FramelessWindowHint);
        this->setAttribute(Qt::WA_TranslucentBackground, true);
    }
    
    DragImage::~DragImage()
    {
        delete ui;
    }
    
    void DragImage::setShowText(QString text)
    {
        ui->pushButton->setText(text);
    }
    
    void DragImage::setShowIcon(QIcon pix)
    {
         ui->pushButton->setIcon(pix);
    }
    
    

    拖拽操作选择界面

    1. 概述
      使用 QButtonGroup 创建一个单选按钮集合,以选择拖拽的操作方式。
    2. 头文件
    #ifndef DRAGMODEDIALOG_H
    #define DRAGMODEDIALOG_H
    
    #include <QDialog>
    
    namespace Ui {
    class DragModeDialog;
    }
    
    class QLabel;
    class QButtonGroup;
    class DragModeDialog : public QDialog
    {
        Q_OBJECT
    
    public:
        explicit DragModeDialog(QWidget *parent = nullptr);
        ~DragModeDialog();
        void setShowText(const QString &dragname,const QString &desname);
        void setShowPixm(const QPixmap &pix);
        enum DragMode { DragAsChild,DragToUp,DragToDown };
        DragMode selMode;
    
    private:
        Ui::DragModeDialog *ui;
        QLabel * iconLabel;
        QLabel * textlabel;
        QButtonGroup * group;
    private slots:
        void buttonOkClick();
        void buttonCancelClick();
    };
    
    #endif // DRAGMODEDIALOG_H
    
    1. 源码文件
    #include "dragmodedialog.h"
    #include "ui_dragmodedialog.h"
    #include <QButtonGroup>
    #include <QRadioButton>
    #include <QDialogButtonBox>
    #include <QPushButton>
    #include <QLabel>
    #include <QGridLayout>
    
    
    DragModeDialog::DragModeDialog(QWidget *parent) :
        QDialog(parent),
        ui(new Ui::DragModeDialog)
    {
        ui->setupUi(this);
        //创建 QRadioButton 集合
        group = new QButtonGroup(this);
        QRadioButton * bnt1 = new QRadioButton(tr("子节点:添加到目标子节点末尾"),this);
        QRadioButton * btn2 = new QRadioButton(tr("同级节点:添加到目标上方位置"),this);
        QRadioButton * btn3 = new QRadioButton(tr("同级节点:添加到目标下方位置"),this);
        bnt1->setChecked(true);
        group->addButton(bnt1,1);
        group->addButton(btn2,2);
        group->addButton(btn3,3);
        //创建标准按钮框
        QDialogButtonBox * box = new QDialogButtonBox(this);
        QPushButton * buttonOk = new QPushButton(tr("确定"));
        QPushButton * buttonCancel = new QPushButton(tr("取消"));
        box->addButton(buttonCancel,QDialogButtonBox::RejectRole);
        box->addButton(buttonOk,QDialogButtonBox::YesRole);
        buttonOk->setDefault(true);
    
        iconLabel = new QLabel(this);
        textlabel = new QLabel(this);
        textlabel->setText(tr("选择拖动的行为:"));
        textlabel->setStyleSheet("color:blue");
        QFont ft;
        ft.setBold(true);
        ft.setPointSize(11);
        textlabel->setFont(ft);
    
        QLabel * tmp = new QLabel(this);
        tmp->setSizePolicy(QSizePolicy::Fixed,QSizePolicy::Fixed);
        QGridLayout *mainLayout = new QGridLayout(this);
        mainLayout->addWidget(iconLabel,0,0,1,1);
        mainLayout->addWidget(textlabel,0,1,1,3);
        mainLayout->addWidget(bnt1,1,0,1,4);
        mainLayout->addWidget(btn2,2,0,1,4);
        mainLayout->addWidget(btn3,3,0,1,4);
        mainLayout->addWidget(tmp,4,0,1,4);
        mainLayout->addWidget(box,5,0,1,4);
        mainLayout->setHorizontalSpacing(10);
        mainLayout->setVerticalSpacing(10);
        mainLayout->setContentsMargins(10,10,10,10);
    
        setLayout(mainLayout);
        this->setFixedSize(380,210);
        this->setWindowTitle(tr("拖动设置"));
        setWindowFlags(Qt::WindowStaysOnTopHint);
    
        connect(buttonOk,&QPushButton::clicked,this,&DragModeDialog::buttonOkClick);
        connect(buttonCancel,&QPushButton::clicked,this,&DragModeDialog::buttonCancelClick);
    }
    
    DragModeDialog::~DragModeDialog()
    {
        delete ui;
    }
    
    void DragModeDialog::setShowText(const QString &dragname, const QString &desname)
    {
        textlabel->setText(QString(tr("拖动节点:%1,目标节点:%2,选择操作类型:")).arg(dragname).arg(desname));
    }
    
    void DragModeDialog::setShowPixm(const QPixmap &pix)
    {
        iconLabel->setPixmap(pix);
    }
    
    void DragModeDialog::buttonOkClick()
    {
        int selID = group->checkedId();
        switch (selID)
        {
            case 1:
                selMode = DragAsChild;
                break;
            case 2:
                selMode = DragToUp;
                break;
            case 3:
                selMode = DragToDown;
                break;
        }
        accept();
    }
    
    void DragModeDialog::buttonCancelClick()
    {
        close();
    }
    
    

    在这里插入图片描述

    展开全文
  • 前言 最近项目需求,需要多个QTreeWidget之间可以相互拖拽,在网上找的demo测试了下却是可行...2. 新建一个类继承于QTreeWidget,重写鼠标按下/鼠标释放/鼠标移动 开始拖拽/拖拽移动/拖拽离开/拖拽放下事件 3. 设置Q
  • Qt读写Xml文件;QTreeWidget加载显示Xml文件内容;QTreeWidget项导出保存为Xml;QTreeWidget项实现可拖动、编辑、创建、删除等
  • QT中在QWidget支持拖拽功能,QTreeWidget继承自QWidget,所以自然也具有节点的拖拽功能。 拖拽包含两个功能:一个是拖动(Drag),一个是放下(Drop)。拖动的数据是QMimeData数据,MIME数据定义格式:类型/数据 ...
  • 要代码实现拖拽使用了QTreeWidget的信号itemClicked和使用了事件dragEnterevent,dragMovEvent,dropEvent满足了,但是还需满足只能移动到父节点上,不能加在子节点上。没想出来,请大佬看看讲讲思路。
  • Qt在QTreeWidget中实现拖动操作

    千次阅读 2018-11-22 14:31:09
    拖动操作分为拖动和放下两种状态 拖动状态主要关于两个事件 void CTreeWidget::mousePressEvent(QMouseEvent *ev) { qDebug()<<"Enter mousePressEvent"; if (ev->button() == Qt::LeftButton) { m_...
  • 文章目录[隐藏] 前言demo 功能demo 代码demo 效果 前言 使用Qt好久了,发现自己还没有用过QTreeWidget。...3. 支持多个树之间拖拽,也支持单个树之间拖拽(非自定义); 4. 列平分。 demo 代码 TreeDrag ...
  • QT中QTreeWidget的拖放操作

    千次阅读 2020-04-28 17:50:58
    在学习Qt的过程中接触过QListWidget和QTextWidget的拖放操作,现QT项目实操需用到树形节点拖放的...class TreeWidget : public QTreeWidget { Q_OBJECT public: explicit TreeWidget(QWidget *parent = nullptr); ...
  • 我需要知道Drag的起始...Drop后的节点落在的节点位置,以及拖拽是如何实现的。 (请大佬附上**_Python_**代码,本人蒟蒻,要是每行能附上注释最好) (并且希望能够有一个整体的QTreeWidget窗口示例来演示这个过程)(T-T)
  • 在公司写完一些关于QTreeWidget的功能之后,突然告知要做一个拖拽的功能。 网上查了一下,大概需要这样做: 1.重写QTreeWidget类 2.重写类中的三个函数 void dragEnterEvent(QDragEnterEvent *event); void ...
  • Qt-TreeWidget拖拽

    2021-01-11 14:41:44
    QT中在QWidget支持拖拽功能,QTreeWidget继承自QWidget,所以自然也具有节点的拖拽功能。 拖拽包含两个功能:一个是拖动(Drag),一个是放下(Drop)。拖动的数据是QMimeData数据,MIME数据定义格式:类型/数据 ...
  • #include "ctreewidget.h" #include #include #define BM_ICON_WIDTH 22 CTreeWidget::CTreeWidget(QWidget *parent) : QTreeWidget(parent),m_child(true),m_newLine(QLine()), m_oldLine(QLine()) { t
  • 第一步,在datatree类(继承自qtreewidget)的构造函数中设置这棵树具有如下两种特征: setDefaultDropAction(Qt::MoveAction); setDragDropMode(QAbstractItemView::DragDrop); 第二步,重写 startdrag()函数,...
  • 一个QTreeWidget和QListWidget使用demo
  • 如题 求一解决方案,主要想把树中选择item拖动至QTabelView控件
  • ui->treeWidget->verticalScrollBar()->setStyleSheet(QString("QScrollBar{background:transparent; width:36px;}"));
  • 我们想把第一个widget里的项目拖动到第二个widget中。由于有子项目的项目其实是一个大类,没有实际意义,所以我们并不想把它拖动到第二个widget,因此,我们想要在禁止用户拖动有子项目的父项目。
  • qt小白花了一整天的时间,翻了网上无数中英文的帖子和博客,最终乱点了一下ui模式下的一个选项而解决了问题… 目标: 实现在一个qtreewidget里item可以自由移动: 1. 拖动到某两个item之间时,可以以top-level插入到...
  • QTreeWidget设计解决没有拖动项问题

    千次阅读 2011-06-22 23:46:00
    http://www.z8soft.com/article/mobile/201105/20110504299610.shtml 前不久诺基亚发布了Qt 4.7,新...最近总有人提了这个问题:设置QTreeWidget的dragDropMode为InternalMove,然后拖动项,希望把dropped的项设为cu
  • Qt读写Xml文件,读取Xml文件内容并显示在QTreeWidget上,保存QTreeWidget内容为Xml文件
  • 同时可以拖拽QTreeWidgetItem用来形成新的层级关系。同时支持从另一个TreeWidget导入到本TreeWidget上面。且维持同样的导入层级关系。 添加实现思路 根据右键选择的QTreeWIdgetItem作为父节点。直接添加新的子节点
  • QT树节点拖拽,支持两个QTreewidget相互拖拽,可以识别拖拽的节点,代码有难度,希望下载的同学多分析
  • 如题,当我QTreeWidget的派生类中实现了拖拽,但是当我拖动后,在本身的TreeWidget中Drag后,我被拖动的节点会从列表中删除,请问我该如何判断我Drag的窗口是不是TreeWidget!
  • QTreeWidget嵌入QLabel

    千次阅读 2018-02-22 16:17:30
    QTreeWidget嵌入QLabelQTreeWidget *tree1 = new QTreeWidget(this);QTreeWidgetItem *itemParent = new QTreeWidgetItem();tree1-&gt;addTopLevelItem(itemParent);QLabel *label1;// label1 = new QLabel(&...
  • 目标是要通过继承QTreeWidget做一个类似QQ的好友列表(即...当把某个QTreeWidgetItem拖拽起时,跟随鼠标的拖拽项是不带有Widget的QTreeWidgetItem。 想问问大家,这时有什么方法可以设置这个跟随鼠标的悬浮项?

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 500
精华内容 200
关键字:

qtreewidget拖拽

友情链接: Máquinas AC.zip