前言

最近项目需求,需要多个QTreeWidget之间可以相互拖拽,在网上找的demo测试了下却是可行,但是这种方法只是针对单个item。

后面我会改造成对多个item(相当于可以复选拖拽)

思路

1. 新建一个继承于QMimeData的类,重写formats和retrieveData的类;新建两个函数,用于getter和setter,MIME的types

2. 新建一个类继承于QTreeWidget,重写鼠标按下/鼠标释放/鼠标移动 开始拖拽/拖拽移动/拖拽离开/拖拽放下事件

3. 设置QTreeWidget必要的属性,如可以拖拽/可以接受拖拽等。具体代码如下

源码

QCMimeData h/cpp

#ifndef QCMIMEDATA_H
#define QCMIMEDATA_H

#include <QMimeData>
#include <QTreeWidgetItem>

class QCMimeData : public QMimeData
{
    Q_OBJECT
public:
    explicit QCMimeData();

    void setDragData(QString mimeType, QTreeWidgetItem *item);
    const QTreeWidgetItem *dragData() const;

    QStringList formats() const override;

protected:
    QVariant retrieveData(const QString &mimetype, QVariant::Type preferredType) const override;

private:
    const QTreeWidgetItem *m_treeItem;
    QStringList m_formats;

};

#endif // QCMIMEDATA_H
#include "qcmimedata.h"

QCMimeData::QCMimeData():
    m_treeItem(nullptr),
    m_formats()
{

}

void QCMimeData::setDragData(QString mimeType, QTreeWidgetItem *item)
{
    m_formats << mimeType;
    m_treeItem = item;
}

const QTreeWidgetItem* QCMimeData::dragData() const
{
    return m_treeItem;
}

QStringList QCMimeData::formats() const
{
    return m_formats;
}

QVariant QCMimeData::retrieveData(const QString &mimetype, QVariant::Type preferredType) const
{
    if(mimetype == m_formats.first())
    {
        return m_treeItem;
    }
    else
    {
        return QCMimeData::retrieveData(mimetype, preferredType);
    }
}

QCTreeWidget h/cpp

#ifndef QCTREEWIDGET_H
#define QCTREEWIDGET_H

#include <QWidget>
#include <QTreeWidget>
#include <QMouseEvent>
#include <QDragEnterEvent>
#include <QDragLeaveEvent>
#include <QDragMoveEvent>
#include <QKeyEvent>
#include <QDropEvent>
#include <QPoint>
#include <QDrag>
#include <QApplication>
#include "qcmimedata.h"


class QCTreeWidget : public QTreeWidget
{
    Q_OBJECT
public:
    explicit QCTreeWidget(QWidget *parent = nullptr);


    void setTreeData();
    void setTreeSettings();

signals:

private:
    void performDrag();

private:
    bool m_ctrlPressed;
    QPoint m_startPoint;


    // QWidget interface
protected:
    void mousePressEvent(QMouseEvent *event);
    void mouseReleaseEvent(QMouseEvent *event);
    void mouseMoveEvent(QMouseEvent *event);
    void keyPressEvent(QKeyEvent *event);
    void keyReleaseEvent(QKeyEvent *event);
    void dragEnterEvent(QDragEnterEvent *event);
    void dragMoveEvent(QDragMoveEvent *event);
    void dragLeaveEvent(QDragLeaveEvent *event);
    void dropEvent(QDropEvent *event);
};

#endif // QCTREEWIDGET_H
#include "qctreewidget.h"

QCTreeWidget::QCTreeWidget(QWidget *parent) :
    QTreeWidget(parent),
    m_ctrlPressed(false)
{
    setTreeData();
    setTreeSettings();
}


void QCTreeWidget::setTreeData()
{


    QTreeWidgetItem* item = nullptr;
    QTreeWidgetItem* itemChild = nullptr;

    for(int i = 0; i < 2; ++i)
    {
        item = new QTreeWidgetItem(this);
        item->setText(0, QString("item_0_%1").arg(i));
        item->setText(1, QString("item_1_%1").arg(i));
        this->addTopLevelItem(item);

        itemChild = new QTreeWidgetItem(item);
        for(int j = 0; j < 2; ++j)
        {
            itemChild->setText(j, QString("itemChild_%1_%2").arg(j).arg(i));
        }
    }
}

void QCTreeWidget::setTreeSettings()
{
    /*QStringList headers;
    headers << "name" << "cmd";
    this->setColumnCount(2);
    this->setHeaderLabels(headers);
    this->setAcceptDrops(true);
    this->setDragEnabled(true);
    this->setSelectionBehavior(QAbstractItemView::SelectRows);*/
}

void QCTreeWidget::performDrag()
{
    QTreeWidgetItem *item = currentItem();
    if(item)
    {
        QCMimeData *mimeData = new QCMimeData;
        mimeData->setDragData("ItemMimeData",item);

        QDrag *drag = new QDrag(this);
        drag->setMimeData(mimeData);

        if (m_ctrlPressed)
        {
            drag->exec(Qt::CopyAction);
        }
        else
        {
            drag->exec(Qt::MoveAction);
            delete item;
        }
    }
}

void QCTreeWidget::mousePressEvent(QMouseEvent *event)
{
    if(event->button() == Qt::LeftButton)
    {
        m_startPoint = event->pos();
    }
    QTreeWidget::mousePressEvent(event);
}

void QCTreeWidget::mouseReleaseEvent(QMouseEvent *event)
{
    QTreeWidget::mouseReleaseEvent(event);
}

void QCTreeWidget::mouseMoveEvent(QMouseEvent *event)
{
    int distance = (event->pos() - m_startPoint).manhattanLength();
    if(distance > QApplication::startDragDistance())
    {
        performDrag();
    }
    QTreeWidget::mouseMoveEvent(event);
}

void QCTreeWidget::keyPressEvent(QKeyEvent *event)
{
    if (event->key() == Qt::Key_Control)
    {
        m_ctrlPressed = true;
    }
}

void QCTreeWidget::keyReleaseEvent(QKeyEvent *event)
{
    if (event->key() == Qt::Key_Control)
    {
        m_ctrlPressed = false;
    }
}

void QCTreeWidget::dragEnterEvent(QDragEnterEvent *event)
{
    QWidget *source =  qobject_cast<QCTreeWidget *>(event->source());
    if (source /*&& source != this*/)
    {
        if (m_ctrlPressed)
        {
            event->setDropAction(Qt::CopyAction);
        }
        else
        {
            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*/)
    {
        const QCMimeData *pMimeData = (const QCMimeData *)(event->mimeData());
        const QTreeWidgetItem *item = pMimeData->dragData();
        QTreeWidgetItem *currentItem = this->itemAt(event->pos());
        if (currentItem == item)           //不允许拖回到原来的item
        {
            event->ignore();
        }
        else
        {
            setCurrentItem(currentItem);
            if (m_ctrlPressed)
            {
                event->setDropAction(Qt::CopyAction);
            }
            else
            {
                event->setDropAction(Qt::MoveAction);
            }
            //event->setDropAction(Qt::MoveAction);
            event->accept();
        }
    }
}

void QCTreeWidget::dragLeaveEvent(QDragLeaveEvent *event)
{
    QTreeWidget::dragLeaveEvent(event);
}

void QCTreeWidget::dropEvent(QDropEvent *event)
{
    QWidget *source =  qobject_cast<QCTreeWidget *>(event->source());
    const QCMimeData *pMimeData = (const QCMimeData *)(event->mimeData());
    if (source /*&& source != this*/)
    {
        const QTreeWidgetItem *item = pMimeData->dragData();
        QTreeWidgetItem *pItem = item->clone();
        QTreeWidgetItem *currentItem = this->itemAt(event->pos());

        if (currentItem && (currentItem != item))
        {
            currentItem->addChild(pItem);
        }
        else
        {
            this->addTopLevelItem(pItem);
        }
        if (m_ctrlPressed)
        {
            event->setDropAction(Qt::CopyAction);
        }
        else
        {
            event->setDropAction(Qt::MoveAction);
        }
        //event->setDropAction(Qt::MoveAction);
        event->accept();
    }
}

TreeDrag h/cpp 真正使用类,使用QCTreeWidget提升QTreeWidget

#ifndef TREEDRAG_H
#define TREEDRAG_H

#include <QWidget>
#include <QTreeWidget>
#include "qctreewidget.h"

namespace Ui {
class TreeDrag;
}

class TreeDrag : public QWidget
{
    Q_OBJECT

public:
    explicit TreeDrag(QWidget *parent = nullptr);
    ~TreeDrag();


private:
    void setTreeSettings(QTreeWidget *treeWidget);
private:
    Ui::TreeDrag *ui;


};

#endif // TREEDRAG_H
#include "treedrag.h"
#include "ui_treedrag.h"

TreeDrag::TreeDrag(QWidget *parent) :
    QWidget(parent),
    ui(new Ui::TreeDrag)
{
    ui->setupUi(this);

    setTreeSettings(ui->treeWidget);
    setTreeSettings(ui->treeWidget_2);
    setTreeSettings(ui->treeWidget_3);

}

TreeDrag::~TreeDrag()
{
    delete ui;
}

void TreeDrag::setTreeSettings(QTreeWidget* treeWidget)
{
    QStringList headers;
    headers << "name" << "cmd";
    treeWidget->setColumnCount(2);
    treeWidget->setHeaderLabels(headers);
    treeWidget->setAcceptDrops(true);
    treeWidget->setDragEnabled(true);
//    treeWidget->setDefaultDropAction(Qt::MoveAction);
    treeWidget->setSelectionBehavior(QAbstractItemView::SelectRows);
    treeWidget->header()->setSectionResizeMode(QHeaderView::Stretch);
    treeWidget->setSelectionMode(QAbstractItemView::ExtendedSelection);
//    treeWidget->setDropIndicatorShown(false); // 显示拖放指示器
}

截图(箭头所指的item即是我拖拽的item)

Qt 多个QTreeWidget之间Item拖拽(单个item)_c/c

原文地址:https://itzhai.cn/xuexijiaocheng/1146.html