Qt自定义控件1:可拖拽排序表格(类似QQ好友分组排序)
来源:互联网 发布:桌面世界时钟软件 编辑:程序博客网 时间:2024/05/16 14:03
1,简介
为了最佳体验,一个拖拽行排序的功能研究了几个小时。效果参考的QQ好友分组的排序。
网上查了下好像没有人发布QT版类似的代码,于是自己动手
QQ好友分组排序效果:
2,效果
这是最终效果图,有小伙伴说看起来很流畅,事实确实是很流畅的。
3,思路
拖拽:就是QT的一套拖拽功能的类,QDrag、QMimeData,和几个鼠标事件和拖拽响应事件:
protected: //根据鼠标事件开启拖拽 void mousePressEvent ( QMouseEvent * event ) ; void mouseMoveEvent(QMouseEvent *event); //拖拽响应事件 void dragEnterEvent(QDragEnterEvent *event); void dragMoveEvent(QDragMoveEvent *event); void dropEvent(QDropEvent *event);
拖拽时的位置指示线:其实就是个高度为2的QLabel,设边框颜色就是该线的颜色。
主要类:一个继承自QTableView的类 MyTableView
MyTableView.h:
#ifndef MYTABLEVIEW_H#define MYTABLEVIEW_H#include <QTableView>#include <QLabel>#include <QMouseEvent>#include <QStandardItemModel>class MyTableView : public QTableView{ Q_OBJECTpublic: MyTableView(QWidget *parent = Q_NULLPTR); //此函数包装了自带的setModel,只是记录了model指针方便内部调用 void SetModel(QStandardItemModel *model);signals: //拖拽结束后会发出此信号,可绑定槽函数实现你的其他功能,比如把新的顺序存到文件 void sigRowChange(int from, int to);protected: //根据鼠标事件开启拖拽 void mousePressEvent ( QMouseEvent * event ) ; void mouseMoveEvent(QMouseEvent *event); //拖拽响应事件 void dragEnterEvent(QDragEnterEvent *event); void dragMoveEvent(QDragMoveEvent *event); void dropEvent(QDropEvent *event);private: void DoDrag(); //执行拖拽 void ResetOrder(); //重置第一列序号 void MoveRow(int from, int to); //真正执行移动行的功能private: QStandardItemModel *mModel; QLabel* mLabel; //高度设为2,用做指示线 int mRowHeight; //表格的行高 bool mValidPress; //在鼠标移动时,判断之前按下时是否是在有效行上int mRowFrom;//拖动起始行 int mRowTo; //拖动时(还没松开时)鼠标位置代表的行,会绘制一条指示线,类似QQ好友列表拖拽效果 QString mDragText; //拖拽过程中跟随鼠标显示的内容 QPoint mDragPoint; //拖拽起点 QPoint mDragPointAtItem; //记录按下时鼠标相对该行的位置,在拖动过程中保持该相对位置};#endif // MYTABLEVIEW_H
MyTableView.cpp:
#include "MyTableView.h"#include <QApplication>#include <QDrag>#include <QMimeData>#include <QPainter>#include <QHeaderView>MyTableView::MyTableView(QWidget *parent) : QTableView(parent){ setAcceptDrops(true);mLabel = new QLabel(this);mLabel->setFixedHeight(2); mLabel->setGeometry(1, 0, width(), 2);mLabel->setStyleSheet("border: 1px solid #8B7500;");mLabel->hide(); mModel = NULL; mRowHeight = 30; mValidPress = false; mRowFrom = 0; mRowTo = 0;}void MyTableView::SetModel(QStandardItemModel *model){ mModel = model; QTableView::setModel(model);}void MyTableView::mousePressEvent(QMouseEvent *e){ if (e->button() == Qt::LeftButton) { QModelIndex index = indexAt(e->pos()); if (index.isValid()) { mValidPress = true; mDragPoint = e->pos(); mDragText = mModel->item(index.row(),1)->text(); mDragPointAtItem = mDragPoint - QPoint(0,index.row()*mRowHeight); mRowFrom = index.row(); } } QTableView::mousePressEvent(e);}void MyTableView::mouseMoveEvent ( QMouseEvent * e ){ if (!mValidPress){return;} if (!(e->buttons() & Qt::LeftButton)) return; if ((e->pos() - mDragPoint).manhattanLength() < QApplication::startDragDistance()) return; mLabel->show(); DoDrag(); //开始拖拽,完成拖拽后才会继续往下走 mLabel->hide(); mValidPress = false;}void MyTableView::dragEnterEvent ( QDragEnterEvent * e ){ if (e->mimeData()->hasText()){ e->acceptProposedAction();}else{ e->ignore(); QTableView::dragEnterEvent(e);}}void MyTableView::dragMoveEvent ( QDragMoveEvent * e ){ if(e->mimeData()->hasText()) {int nCurRow = 0; QModelIndex index = indexAt(e->pos()); if (index.isValid()) { if(e->pos().y() - index.row()*mRowHeight >= mRowHeight/2) { nCurRow = index.row() + 1; } else { nCurRow = index.row(); } } else {nCurRow = mModel->rowCount(); }// if (nCurRow != mRowFrom){ mRowTo = nCurRow;mLabel->setGeometry(1, mRowTo*mRowHeight, width() - 2, 2);} e->acceptProposedAction();return; } e->ignore(); QTableView::dragMoveEvent(e);}void MyTableView::dropEvent ( QDropEvent * e ){ if(e->mimeData()->hasText()) { if (mRowTo != mRowFrom) { MoveRow(mRowFrom, mRowTo);} e->acceptProposedAction();return; } e->ignore(); QTableView::dropEvent(e);}void MyTableView::DoDrag(){ QDrag *drag = new QDrag(this); QMimeData *mimeData = new QMimeData; mimeData->setText(mDragText); drag->setMimeData(mimeData); // 设置拖拽图片 QPixmap drag_img(width(), mRowHeight); drag_img.fill(QColor(255,255,255,100)); QPainter painter(&drag_img); painter.setPen(QColor(0, 0, 0, 200)); painter.drawText(QRectF(40,0,width(),mRowHeight), mDragText, QTextOption(Qt::AlignVCenter)); drag->setPixmap(drag_img); drag->setHotSpot(mDragPointAtItem); //***注意:此句会阻塞,进入drag的拖拽消息循环,会依次触发dragEnterEvent、dragMoveEvent、dropEvent消息 if (drag->exec(Qt::MoveAction) == Qt::MoveAction) { // 确认移动操作 }}void MyTableView::ResetOrder(){for (int i = 0; i < mModel->rowCount(); i++){ mModel->item(i, 0)->setText( QString::number(i + 1) );}}void MyTableView::MoveRow(int from, int to){if (from == to){return;}QStandardItem * item = mModel->item(from, 1);if (item){ QString strText = item->text();QList<QStandardItem*> items;QStandardItem* item0 = new QStandardItem(""); QStandardItem* item1 = new QStandardItem(strText);items.append(item0);items.append(item1); item0->setTextAlignment(Qt::AlignCenter); //移动行思路:就是先在要移动到的位置新建同样内容的行,然后删除被移动的行mModel->insertRow(to, items);if (from < to){mModel->removeRow(from);selectRow(to-1);}else{mModel->removeRow(from+1);selectRow(to);}ResetOrder(); emit sigRowChange(mRowFrom,mRowTo);}}
在MainWindow上放一个QTableView然后提升为该MyTableView,MainWindow里做些初始化:
MainWindow.cpp:
#include "MyTableView.h"#include "mainwindow.h"#include "ui_mainwindow.h"MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent), ui(new Ui::MainWindow){ ui->setupUi(this); InitTable();}MainWindow::~MainWindow(){ delete ui;}void MainWindow::InitTable(){ MyTableView* t = ui->tableView; //设置各种属性 t->horizontalHeader()->hide();//隐藏列头(带列头的情况需要修改代码,重新计算高度偏移) t->verticalHeader()->hide();//隐藏行头 t->verticalHeader()->setDefaultSectionSize(30); //默认列高度 t->horizontalHeader()->setStretchLastSection(true); //最后一列自适应宽度 t->setEditTriggers(QTableView::NoEditTriggers);//不能编辑 t->setSelectionBehavior(QTableView::SelectRows);//一次选中整行 t->setSelectionMode(QTableView::SingleSelection); //单行选中 t->setAlternatingRowColors(true); //行间隔色 t->setShowGrid(false); //去掉网格线 t->setFocusPolicy(Qt::NoFocus); //去掉item选中时虚线框 //添加数据 QStandardItemModel* model = new QStandardItemModel(); model->setHorizontalHeaderItem(0, new QStandardItem(QStringLiteral("序号"))); model->setHorizontalHeaderItem(1, new QStandardItem(QStringLiteral("内容"))); QStringList strs; strs<<"111"<<"222"<<"333"<<"444"<<"AAA"<<"BBB"<<"CCC"<<"DDD"; for(int i=0;i<strs.size();i++) { model->setItem(i, 0, new QStandardItem(QString::number(i+1))); model->setItem(i, 1, new QStandardItem(strs[i])); model->item(i, 0)->setTextAlignment(Qt::AlignCenter); } t->SetModel(model); //设置样式 t->setStyleSheet("QTableView {border: 1px solid gray;background: #E8E8E8;}\ QTableView::item{color:black;}\ QTableView::item:selected{color:black;background: #63B8FF;}"); t->setColumnWidth(0,40); t->selectRow(0);}
4,源码下载
百度网盘:https://pan.baidu.com/s/1dFeqbYT
注:Demo使用QT5.8+MinGW编译通过。
阅读全文
1 0
- Qt自定义控件1:可拖拽排序表格(类似QQ好友分组排序)
- 类似QQ好友分组栏
- 好友列表排序,分组
- Qt实现类似QQ好友列表
- 自定义UITableViewCell,实现类似QQ好友列表
- iOS 中文首字母排序,通讯录排序,好友分组排序
- iOS 中文首字母排序,通讯录排序,好友分组排序
- hadoop自定义排序,分组排序
- 猜想 QQ好友分组 (微信好友)多层次分组策略 QQ好友过多
- QQ好友分组添加好友(UITableView实现)
- (VIEW控件)Android之实现QQ好友分组(ExpandableListView)
- 自定义view 类似QQ好友来消息的动画效果
- 自定义表格排序(JS)
- 自定义分区、数据类型、排序、分组
- Hadoop 自定义排序,自定义分区,自定义分组
- 通讯录的原型实现(二)- 类似QQ好友列表实现,分组名悬浮在最顶部
- QQ 添加分组 添加好友
- Pyqt4下使用QListWidget控件实现的类似QQ好友列表效果控件
- 内核源码阅读(四)进程ID
- 浏览器兼容问题的解决
- 复习_vim笔记
- CentOS7部署tomcat9+jre8+mysql5.7
- Watto and Mechanism(字符串hash算法)
- Qt自定义控件1:可拖拽排序表格(类似QQ好友分组排序)
- AJAX面试汇总
- Linux IO模型分析(一)
- Flex 布局教程:语法篇
- Flex 布局教程:实例篇
- 内存溢出和内存泄漏的区别
- 用clearfix:after消除(DIV块因内部浮动而高度收缩的问题)
- 多线程同步器AQS
- POJ.1222 EXTENDED LIGHTS OUT(高斯消元 异或方程组)