刚进公司没多久,老大就让做一个实现拖放的小插件,要求可拖拽,可缩放。从网上查了很多资料,也看了别人写的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(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(event->source());
if (source /*&& source != this*/)
{
event->setDropAction(Qt::MoveAction);
event->accept();
}
}
void QCTreeWidget::dropEvent(QDropEvent *event)
{
QCTreeWidget *source = qobject_cast(event->source());
if (source /*&& source != this*/)
{
QCTreeWidget *source = qobject_cast(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("放下的文本是: ")<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()<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()<
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;
}