QT实现可拖拽表格控件TableWidget
看到网上很多用上下箭头和按钮来实现TableWidget的拖动排序,我觉得好low,这种操作,我要是客户,我嫌弃。以下给大家介绍:鼠标长按拖拽、插入的TableWidget。
一、需要重写的事件
protected:
//鼠标事件开启拖拽
void mousePressEvent(QMouseEvent* event);
void mouseMoveEvent(QMouseEvent* event);
//拖拽响应事件
void dragEnterEvent(QDragEnterEvent* event);
void dragMoveEvent(QDragMoveEvent* event);
void dropEvent(QDropEvent* event);
二、声明的属性变量
bool m_validPress; //在鼠标移动时,判断之前按下时是否是在有效行上
int m_rowFrom; //起始行
int m_rowTo; //目标行
QString m_dragText; //item
QPoint m_dragPoint; //拖拽起点
三、关键代码的示例
-
先在mousePressEvent里判断鼠标的操作,比如我这里是左键:
if (e->button() == Qt::LeftButton) { QModelIndex index = indexAt(e->pos()); if (index.isValid()) { m_validPress = true; m_dragPoint = e->pos(); m_dragText = this->item(index.row(), 1)->text(); m_rowFrom = index.row(); } } QTableWidget::mousePressEvent(e);
-
接着在mouseMoveEvent里面判断有效性后,开始drag拖动操作:
if (!m_validPress) { return; } if (!(e->buttons() & Qt::LeftButton)) { return; } if ((e->pos() - m_dragPoint).manhattanLength() < QApplication::startDragDistance()) { return; } DoDrag(); //拖拽 m_validPress = false;
-
DoDrag代码,用QMimeData来传递:
QDrag* drag = new QDrag(this); QMimeData* mimeData = new QMimeData; mimeData->setText(m_dragText); drag->setMimeData(mimeData); if (drag->exec(Qt::MoveAction) == Qt::MoveAction) { } delete drag;
-
dragEnterEvent:
if (e->mimeData()->hasText()) { e->acceptProposedAction(); } else { e->ignore(); QTableWidget::dragEnterEvent(e); }
-
dragMoveEvent:
if (e->mimeData()->hasText()) { int nCurRow = 0; QModelIndex index = indexAt(e->pos()); if (index.isValid()) { if (e->pos().y() - index.row()*rowHeight(m_rowFrom) >= rowHeight(m_rowFrom) / 2) { nCurRow = index.row() + 1; } else { nCurRow = index.row(); } } else { if (this->rowCount() >= 1) { nCurRow = this->rowCount() - 1; } } { m_rowTo = nCurRow; int scrollValue = this->verticalScrollBar()->value(); int offsetValue = 0; if (scrollValue > 0 && scrollValue >= this->verticalScrollBar()->maximum()) { scrollValue = scrollValue - 1; offsetValue = (this->height() - horizontalHeader()->height()) % rowHeight(m_rowFrom) - 3; } else { scrollValue = scrollValue > 0 ? scrollValue - 1 : scrollValue; } } e->acceptProposedAction(); return; } e->ignore(); QTableWidget::dragMoveEvent(e);
-
dropEvent:
if (this->rowCount() <= 1) { return; } if (e->mimeData()->hasText()) { if (m_rowTo != m_rowFrom) { if (this->verticalScrollBar()->value() > 0) { //调用你自己的操作,比如我的是更新TableWidget的顺序,发信号给外界 } else { //调用你自己的操作,比如我的是更新TableWidget的顺序,发信号给外界 } m_rowTo = -1; m_rowFrom = -1; } e->acceptProposedAction(); return; } e->ignore(); QTableWidget::dropEvent(e);
到这里基本就完成了,我的功能里其实还有显示一条高亮的拖拽提示线,提示当前拖拽数据的落脚点在哪一个位置,这个你们可以自己加在dragMoveEvent里面,在移动的时候更新提示的位置,也可以在鼠标按下的时候就显示,都行。
四、注意点
大多是根据数据的复杂度、还有需求来的,我这里的数据比较复杂,拖拽的影响范围较广,还有很多给外部的信号槽交互,所以很多有很多要注意的地方。
- 注意对from起始行的有效性判断;
- 注意在插入的时候,要把from的数据删了,不然你的功能就是复制插入,而不是排序了;
- 还有注意外界与本控件的信号槽关系,拖拽结束会不会改变selectRow,对应的槽函数处理;
- 忘了,反正还有几点吧,坑自己踩踩就知道了。
祝大家造出更好的软件。