123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228 |
- #include "dragabletable.h"
- #include <QDrag>
- #include <QMimeData>
- #include <QUuid>
- #include <QDebug>
- #include <QtEvents>
- #include <QPainter>
- #include <QHeaderView>
- #include "../PaintHelper/painthelper.h"
- DragableTable::DragableTable(QWidget *parent)
- : QTableView(parent)
- , m_UUID(QUuid::createUuid())
- , m_bSignalOnly(false)
- , m_bDragEnable(true)
- , m_nTargetRow(-1)
- , m_bIsUpon(false)
- {
- SetDragTargetRow(-1);
- setAcceptDrops(true);
- }
- void DragableTable::SetDragEnable(bool value)
- {
- setAcceptDrops(value);
- m_bDragEnable = value;
- }
- //某行之下或之上
- void DragableTable::SetDragTargetRow(int row, bool isUpon)
- {
- if(!m_bDragEnable) return;
- DragableTableDelegate *pDelegate = dynamic_cast<DragableTableDelegate*>(itemDelegate());
- if(pDelegate == nullptr) return;
- pDelegate->SetDragTarget(row, isUpon);
-
- // setProperty("dragTargetRow", row);
- // setProperty("isUpon", isUpon);
- m_nTargetRow = row;
- m_bIsUpon = isUpon;
- update();
- }
- void DragableTable::mouseMoveEvent(QMouseEvent *event)
- {
- QTableView::mouseMoveEvent(event);
- if(!m_bDragEnable) return;
- if(!m_indexPressed.isValid()) return;
- //启动Drag事件
- QDrag *drag = new QDrag(this);
- QMimeData *mimeData = new QMimeData();
- mimeData->setText(m_UUID.toString());
- drag->setMimeData(mimeData);
- drag->exec(Qt::MoveAction, Qt::CopyAction);
- m_indexPressed = QModelIndex();
- SetDragTargetRow(-1);
- }
- void DragableTable::mousePressEvent(QMouseEvent *event)
- {
- QTableView::mousePressEvent(event);
- if(!m_bDragEnable) return;
- //只允许左键按住
- if(event->button() != Qt::LeftButton) return;
-
- //根据触发鼠标位置获得QModelIndex
- m_indexPressed = indexAt(event->pos());
- }
- void DragableTable::mouseReleaseEvent(QMouseEvent *event)
- {
- QTableView::mouseReleaseEvent(event);
- if(!m_bDragEnable) return;
- m_indexPressed = QModelIndex();
- SetDragTargetRow(-1);
- }
- void DragableTable::dragEnterEvent(QDragEnterEvent *event)
- {
- if(!m_bDragEnable) return;
- const QMimeData *mimeData = event->mimeData();
- if(mimeData == nullptr || !mimeData->hasText()) return;
- if(event->mimeData()->text() != m_UUID.toString()) return;
-
- {//下面内容和dragMoveEvent里的一样, 避免dragMoveEvent未被调用而直接进入dropEvent
- QModelIndex index = indexAt(event->pos());
- int row = -1;
- //如拖拽到表格的空白位置, 视为目标是最后一行之下
- if(!index.isValid())
- {
- row = model()->rowCount() - 1;
- SetDragTargetRow(row, false);
- }
- else
- {
- QRect indexRect = visualRect(index);
- int rowHeight = verticalHeader()->sectionSize(index.row());
- int center = indexRect.top() + rowHeight/2;
- SetDragTargetRow(index.row(), event->pos().y()<=center);
- }
- }
- event->accept();
- }
- void DragableTable::dragMoveEvent(QDragMoveEvent *event)
- {
- if(!m_bDragEnable) return;
- QModelIndex index = indexAt(event->pos());
- int row = -1;
- //如拖拽到表格的空白位置, 视为目标是最后一行之下
- if(!index.isValid())
- {
- row = model()->rowCount() - 1;
- SetDragTargetRow(row, false);
- }
- else
- {
- QRect indexRect = visualRect(index);
- int rowHeight = verticalHeader()->sectionSize(index.row());
- int center = indexRect.top() + rowHeight/2;
- SetDragTargetRow(index.row(), event->pos().y()<=center);
- }
- }
- void DragableTable::dropEvent(QDropEvent *event)
- {
- if(!m_bDragEnable) return;
- /*----------------------------------------------------------------
- * 设置QDrag::exec()的返回值, 必须配合accept使用
- * 也可以直接调用acceptProposedAction方法来将返回值设为调用QDrag::exec时传入的defaultDropAction
- * event->setDropAction(Qt::MoveAction);
- * event->accept();
- * 不管之前执行了accept还是acceptProposedAction, 只要执行了event->ignore, QDrag::exec()的返回值都会是Qt::IgnoreAction
- * event->ignore();
- ----------------------------------------------------------------*/
- do
- {
- int sourceRow = m_indexPressed.row();
- if(m_nTargetRow == -1) break;
- if(sourceRow == m_nTargetRow) break;
-
- //计算实际要插入到的行: 如果是插入到"之下", 则要加1; 如果把上方的行往下移, 则要减1
- int insertedRow = m_nTargetRow + (m_bIsUpon?0:1) - ((sourceRow>m_nTargetRow)?0:1);
- if(sourceRow == insertedRow) break;
-
- //发送信号
- emit sig_Drop(sourceRow, insertedRow);
- if(m_bSignalOnly) break;
-
- QStandardItemModel *pModel = dynamic_cast<QStandardItemModel*>(model());
- if(pModel == nullptr) break;
-
- QList<QStandardItem*> targetRowItems = pModel->takeRow(sourceRow);
- if(!targetRowItems.isEmpty()) pModel->insertRow(insertedRow, targetRowItems);
-
- /*----------------------------------------------------------------
- * 另一种思路:先交换源行和目标行的数据, 交换后目标行去到了源行, 其他行不受影响; 再将目标行移到当前源行位置之后
- ----------------------------------------------------------------*/
-
- }while (false);
-
- m_indexPressed = QModelIndex();
- SetDragTargetRow(-1);
- event->acceptProposedAction();
- }
- DragableTableDelegate::DragableTableDelegate(QObject *parent)
- : BaseItemDelegate(parent)
- // , m_pTableView(parentTable)
- , m_nTargetRow(-1)
- , m_bIsUpon(false)
- {
-
- }
- void DragableTableDelegate::SetDragTarget(int targetRow, bool isUpon)
- {
- m_nTargetRow = targetRow;
- m_bIsUpon = isUpon;
- }
- void DragableTableDelegate::paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const
- {
- BaseItemDelegate::paint(painter,option,index);
-
- if(m_nTargetRow == -1) return;
- PainterEx *painterEx = static_cast<PainterEx*>(painter);
-
- //绘制第一列单元格圆圈和线
- if(index.row() == m_nTargetRow && index.column() == 0)
- {
- int y = m_bIsUpon?option.rect.top():option.rect.bottom();
- painterEx->DrawCircle(QPoint(km_nRadius, y), km_nRadius, Qt::transparent, QPen(QColor(86,135,228), 2));
- painterEx->setPen(QPen(QColor(86,135,228), 2));
- painterEx->drawLine(option.rect.left()+km_nRadius*2, y, option.rect.right(), y);
- }
- //如果指示器绘制在当前行的下方, 因为头部圆圈会跨到下一行, 所以在绘制下一行的时候, 又绘制一次
- if(!m_bIsUpon && (index.row() == m_nTargetRow+1) && index.column() == 0)
- {
- int y = option.rect.top() - 1;
- painterEx->DrawCircle(QPoint(km_nRadius, y), km_nRadius, Qt::transparent, QPen(QColor(86,135,228), 2));
- painterEx->setPen(QPen(QColor(86,135,228), 2));
- painterEx->drawLine(option.rect.left()+km_nRadius*2, y, option.rect.right(), y);
- }
- //绘制后面单元格的线
- if(index.row() == m_nTargetRow && index.column() != 0)
- {
- painterEx->DrawBorder(option.rect, QPen(QColor(86,135,228), 2), m_bIsUpon?PainterEx::RectBorderTop:PainterEx::RectBorderBottom);
- }
-
- // //绘制拖拽指示器(绘制2*列数次, 防止被覆盖)
- // if(index.row() == m_nTargetRow||index.row() == m_nTargetRow+1)
- // {
- // painter->setRenderHint(QPainter::Antialiasing);
- // painter->setPen(QPen(QColor(86,135,228), 2));
- // painter->setBrush(Qt::transparent);
-
- // //int rowCount = m_pTableView->model()->rowCount();
- // int colCount = m_pTableView->model()->columnCount();
- // QPoint targetRowRect_topLeft = m_pTableView->visualRect(m_pTableView->model()->index(row,0)).topLeft();
- // QPoint targetRowRect_bottomRight = m_pTableView->visualRect(m_pTableView->model()->index(row,colCount-1)).bottomRight();
- // QRect targetRowRect(targetRowRect_topLeft, targetRowRect_bottomRight);
-
- // //头部圆圈
- // int radius = 8;
- // int y = m_bIsUpon?targetRowRect.top():targetRowRect.bottom();
- // QPoint topleft = QPoint(targetRowRect.left(), y - radius);
- // painter->drawEllipse(QRect(topleft, QSize(radius*2, radius*2)));
- // painter->drawLine(targetRowRect.left()+radius*2, y, targetRowRect.right(), y);
- // }
- }
|