QT 自定义模型实现拖拽

自定义模型的拖动

便捷类的拖动实现很简单,今天我们介绍自己定义的ListModel模型如何实现拖动。在之前的ListModel项目基础上,我们先对View视图实现拖动操作.
<!--more-->

  1. //设置选择模式为单选
  2. listView.setSelectionMode(QAbstractItemView::ExtendedSelection);
  3. //设置可拖拽
  4. listView.setDragEnabled(true);
  5. //设置可拖放
  6. listView.setAcceptDrops(true);
  7. //设置显示拖放位置
  8. listView.setDropIndicatorShown(true);

对模型实现拖动

在ListModel添加声明

  1. //编写拖动逻辑
  2. virtual QStringList mimeTypes() const;
  3. virtual QMimeData *mimeData(const QModelIndexList &indexes) const;
  4. virtual bool dropMimeData(const QMimeData *data, Qt::DropAction action,
  5. int row, int column, const QModelIndex &parent);
  6. virtual Qt::DropActions supportedDropActions() const;

自定义一个类型,用来表示拖动导出的类型

  1. //拖放时导出的类型
  2. QStringList StringListModel:: mimeTypes() const{
  3. QStringList types;
  4. //自定义类型
  5. types << "application/zack.list";
  6. return types;
  7. }

将拖动的数据放入mimedata中

  1. QMimeData *StringListModel::mimeData(const QModelIndexList &indexes) const
  2. {
  3. QMimeData * mimeData = new QMimeData();
  4. //字节数组
  5. QByteArray encodeData;
  6. QDataStream stream(&encodeData, QIODevice::WriteOnly);
  7. foreach(const QModelIndex& index, indexes){
  8. if(index.isValid()){
  9. QString text = data(index, Qt::DisplayRole).toString();
  10. stream << text;
  11. }
  12. }
  13. //将数据放入到QMimeData中
  14. mimeData->setData("application/zack.list", encodeData);
  15. return mimeData;
  16. }

将拖放的数据从mimedata中导出

  1. bool StringListModel::dropMimeData(const QMimeData *data, Qt::DropAction action, int row, int column, const QModelIndex &parent)
  2. {
  3. //如果放入的动作是ignoreaction
  4. if(action == Qt::IgnoreAction){
  5. return true;
  6. }
  7. //如果数据的格式不是指定的格式,那么返回false
  8. if(!data->hasFormat("application/zack.list")){
  9. return false;
  10. }
  11. //因为这里是列表, 只用一列, 所以列大于0时返回false
  12. if(column > 0){
  13. return false;
  14. }
  15. //设置开始插入行
  16. int beginRow;
  17. if(row != -1){
  18. beginRow = row;
  19. }else if(parent.isValid()){
  20. beginRow = parent.row();
  21. }else {
  22. beginRow = rowCount(QModelIndex());
  23. }
  24. //将数据从QMimeData 中读取出来, 然后插入到模型中
  25. QByteArray encodeData = data->data("application/zack.list");
  26. //stream流
  27. QDataStream stream(&encodeData, QIODevice::ReadOnly);
  28. //统计插入的数据
  29. QStringList newItems;
  30. //统计插入的行数
  31. int rows = 0;
  32. while(!stream.atEnd()){
  33. QString text;
  34. stream >> text;
  35. newItems << text;
  36. ++ rows;
  37. }
  38. //插入指定行数
  39. insertRows(beginRow, rows, QModelIndex());
  40. //批量修改行数数据
  41. foreach(const QString& text, newItems){
  42. QModelIndex idx = index(beginRow, 0, QModelIndex());
  43. setData(idx,text);
  44. beginRow++;
  45. }
  46. return true;
  47. }

为了能让我们的item拖动,需要重新实现flags变量,使其支持拖放

  1. Qt::ItemFlags StringListModel::flags(const QModelIndex& index) const{
  2. //索引无效可以接受放入操作
  3. if(!index.isValid())
  4. return Qt::ItemIsEnabled | Qt::ItemIsDropEnabled;
  5. //索引有效,可以接受拖拽和放入操作
  6. return QAbstractItemModel::flags(index) | Qt::ItemIsEditable
  7. | Qt::ItemIsDragEnabled | Qt::ItemIsDropEnabled;
  8. }

然后我们设置支持的拖放动作为移动和复制

  1. Qt::DropActions StringListModel::supportedDropActions() const
  2. {
  3. //设置支持放入动作,允许copy和move
  4. return Qt::CopyAction | Qt::MoveAction;
  5. }

拖动效果
https://cdn.llfc.club/%E5%BE%AE%E4%BF%A1%E5%9B%BE%E7%89%87_20221223114425.jpg

源码链接

源码链接
https://gitee.com/secondtonone1/qt-learning-notes

热门评论

热门文章

  1. 解密定时器的实现细节

    喜欢(566) 浏览(1849)
  2. C++ 类的继承封装和多态

    喜欢(588) 浏览(2574)
  3. slice介绍和使用

    喜欢(521) 浏览(1717)
  4. Linux环境搭建和编码

    喜欢(594) 浏览(5498)
  5. windows环境搭建和vscode配置

    喜欢(587) 浏览(1711)

最新评论

  1. 双链表实现LRU算法 secondtonone1:双链表插入和删除节点是本篇的难点,多多练习即可。
  2. 线程安全的无锁栈 secondtonone1:谢谢支持,如果pop的次数大于push的次数是会让线程处于重试的,这个是测试用例,必须满足push和pop的次数相同,实际情况不会这么使用。栈的设计没有问题。
  3. 再谈单例模式 secondtonone1:是的,C++11以后返回局部static变量对象能保证线程安全了。
  4. Linux环境搭建和编码 恋恋风辰:Linux环境下go的安装比较简单,可以不用设置GOPATH环境变量,后期我们学习go mod 之后就拜托了go文件目录的限制了。
  5. C++ 类的拷贝构造、赋值运算、单例模式 secondtonone1:好的,已修复。

个人公众号

个人微信