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) 浏览(2327)
  2. C++ 类的继承封装和多态

    喜欢(588) 浏览(3253)
  3. Linux环境搭建和编码

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

    喜欢(587) 浏览(1871)
  5. slice介绍和使用

    喜欢(521) 浏览(1945)

最新评论

  1. asio多线程模型IOServicePool Lion:线程池一定要继承单例模式吗
  2. 泛型算法的定制操作 secondtonone1:lambda和bind是C11新增的利器,善于利用这两个机制可以极大地提升编程安全性和效率。
  3. 类和对象 陈宇航:支持!!!!
  4. C++ 虚函数表原理和类成员内存分布 WangQi888888:class Test{ int m; int b; }中b成员是int,为什么在内存中只占了1个字节。不应该是4个字节吗?是不是int应该改为char。这样的话就会符合图上说明的情况
  5. 解决博客回复区被脚本注入的问题 secondtonone1:走到现在我忽然明白一个道理,无论工作也好生活也罢,最重要的是开心,即使一份安稳的工作不能给我带来事业上的积累也要合理的舍弃,所以我还是想去做喜欢的方向。

个人公众号

个人微信