Qt 多个QTreeWidget之间Item拖拽(单个item)
前言
最近项目需求,需要多个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); // 显示拖放指示器
}