zoukankan      html  css  js  c++  java
  • Qt之QAbstractItemView视图项拖拽(二)

    一、需求说明   

        上一篇文章Qt之QAbstractItemView视图项拖拽(一)讲述了实现QAbstractItemView视图项拖拽的一种方式,是基于QDrag实现的,这个类是qt自己封装好了的,所以可定制性也就没有了那么强,最明显的是,这个类在执行exec方法后,mouse系列的回调接口就被阻塞了,随之而来的问题就是拖拽时item项没有了hover特性,为了解决这个问题,我们就不能使用QDrag类来实现拖拽了,这也是这篇文章我要讲述的内容。

    二、效果展示  

        如图1是demo的效果展示,比较丑,如果加上优秀的qss,那必然能让人眼前一亮

    图1 ListWidget拖拽


    三、实现思路

    1. 继承QListWidget类,重写其鼠标多拽时几个虚方法,分别是mousePressEvent(鼠标按下),mouseMoveEvent(鼠标移动),mouseReleaseEvent(鼠标弹起)等,当然还包括一些辅助的回调方法enterEvent和leaveEvent。
    2. 鼠标按下时,记录鼠标按下位置和鼠标点击项
    3. 鼠标移动时移动插入项标示和item项快照位置,并修改鼠标形状
    4. 最后鼠标释放时,判断如果需要更新拖拽项位置,那么把原有项删除,并构造新的项插入到目标位置

          上边的几个步骤描述都是在mouse系列的回到接口中发生的,再也没有QDrag的事儿啦。当然这个mouse方法中需要做一些鼠标状态维护等。

    四、代码说明

        1、重要的类和上一篇文章中的一样,忘记的小伙伴可以到上一篇文章查看,或者猛戳Qt之QAbstractItemView视图项拖拽(一)
        2、下面就直接上代码
        a、记录鼠标按下时信息

     1 void DragList::mousePressEvent(QMouseEvent * event)
     2 {
     3     if (event->button() == Qt::LeftButton)
     4     {
     5         m_LeftPress = true;
     6         startPos = event->pos();
     7         dragItem = itemAt(event->pos());
     8     }
     9 
    10     QListWidget::mousePressEvent(event);
    11 }

        b、鼠标移动时维护鼠标状态、快照位置和插入表示位置

     1 void DragList::mouseMoveEvent(QMouseEvent * event)
     2 {
     3     QListWidgetItem * item = itemAt(event->pos());
     4     if (dragItem == nullptr)
     5     {
     6         dragItem = itemAt(event->pos());
     7     }
     8 
     9     if (m_ShotPicture == nullptr)
    10     {
    11         InitShotLabel();
    12     }
    13     if (m_ShotLine == nullptr)
    14     {
    15         InitShotLine();
    16     }
    17 
    18     QRect rect = visualItemRect(dragItem);
    19     if (ListItem * hoverWidget = ItemWidget(item))
    20     {
    21         QRect hoverRect = visualItemRect(item);
    22         QPoint pos = hoverWidget->mapFromParent(event->pos());
    23         if (hoverRect.size().height() / 2 < pos.y())
    24         {
    25             m_ShotLine->move(mapToGlobal(QPoint(2, hoverRect.y() + hoverRect.height() + 1)));
    26         }
    27         else
    28         {
    29             m_ShotLine->move(mapToGlobal(QPoint(2, hoverRect.y() + 1)));
    30         }
    31         
    32         m_ShotLine->setVisible(hoverRect.contains(event->pos()));
    33     }
    34 
    35     if (ListItem * newWidget = ItemWidget(dragItem))
    36     {
    37         m_ShotPicture->move(mapToGlobal(event->pos() - newWidget->mapFromParent(startPos)));
    38         if (rect.contains(event->pos()) || event->pos().isNull())
    39         {
    40             setCursor(Qt::ForbiddenCursor);
    41         }
    42         else
    43         {
    44             setCursor(Qt::ArrowCursor);
    45         }
    46         if (m_ShotPicture->isHidden())
    47         {
    48             m_ShotPicture->show();
    49         }
    50     }
    51 
    52 
    53 //    QListWidget::mouseMoveEvent(event);
    54 }

        c、鼠标释放时处理拖拽结果

     1 void DragList::mouseReleaseEvent(QMouseEvent * event)
     2 {
     3     if (event->button() == Qt::LeftButton)
     4     {
     5         m_LeftPress = false;
     6         if (m_ShotPicture)
     7         {
     8             m_ShotPicture->close();
     9             m_ShotPicture->deleteLater();
    10             m_ShotPicture = nullptr;
    11         }
    12         if (m_ShotLine)
    13         {
    14             m_ShotLine->close();
    15             m_ShotLine->deleteLater();
    16             m_ShotLine = nullptr;
    17         }
    18         MouseRelease(event);
    19     }
    20 
    21     setCursor(Qt::ArrowCursor);
    22 
    23     QListWidget::mouseReleaseEvent(event);
    24 }

        d、初始化跟随鼠标移动的快照,并把当前拖拽的窗口截图设置给快照

     1 void DragList::InitShotLabel()
     2 {
     3     m_ShotPicture = new QLabel;
     4     m_ShotPicture->setWindowOpacity(0.95);
     5     m_ShotPicture->setWindowFlags(Qt::FramelessWindowHint | Qt::Tool | Qt::WindowStaysOnTopHint);
     6     m_ShotPicture->setAttribute(Qt::WA_TransparentForMouseEvents, true);
     7 
     8     if (ListItem * oldWidget = ItemWidget(dragItem))
     9     {
    10         m_ShotPicture->setPixmap(oldWidget->grab());
    11         m_ShotPicture->resize(visualItemRect(dragItem).size());
    12     }
    13     m_ShotPicture->show();
    14 }

        e、初始化鼠标插入位置标示

     1 void DragList::InitShotLine()
     2 {
     3     m_ShotLine = new QLabel;
     4     m_ShotLine->setObjectName(QStringLiteral("ShotLine"));
     5     m_ShotLine->setWindowFlags(Qt::FramelessWindowHint | Qt::Tool | Qt::WindowStaysOnTopHint);
     6     m_ShotLine->setAttribute(Qt::WA_TransparentForMouseEvents, true);
     7     m_ShotLine->setStyleSheet("QLabel#ShotLine{background:green;}");//用图片代替
     8     
     9     if (ListItem * oldWidget = ItemWidget(dragItem))
    10     {
    11     //    m_ShotLine->setPixmap(oldWidget->grab());
    12         m_ShotLine->resize(visualItemRect(dragItem).size().width(), 2);
    13     }
    14     m_ShotLine->show();
    15 }

        f、鼠标弹起具体处理函数

     1 void DragList::MouseRelease(QMouseEvent * event)
     2 {
     3     QListWidgetItem * item = itemAt(event->pos()); 
     4     if (item == nullptr || item == dragItem)
     5     {
     6         return;
     7     }
     8 
     9     int insertPos = row(item);
    10     if (ListItem * oldWidget = ItemWidget(item))
    11     {
    12         QPoint pos = oldWidget->mapFromParent(event->pos());
    13         if (oldWidget->size().height() / 2 < pos.y())
    14         {
    15             insertPos += 1;
    16         }
    17     }
    18 
    19     if (dragItem)
    20     {
    21         if (ListItem * oldWidget = ItemWidget(dragItem))
    22         {
    23             QListWidgetItem * newItem = new QListWidgetItem;
    24             ListItem * itemWidget = new ListItem;
    25             itemWidget->SetData(oldWidget->GetData());
    26 
    27             insertItem(insertPos, newItem);
    28             setItemWidget(newItem, itemWidget);
    29 
    30             setCurrentItem(newItem);
    31 
    32             oldWidget->deleteLater();
    33         }
    34 
    35         dragItem = takeItem(row(dragItem));
    36         if (dragItem)
    37         {
    38             delete dragItem;
    39             dragItem = nullptr;
    40         }
    41     }
    42 }

    五、下载链接 

        Qt之QAbstractItemView视图项拖拽2 

    六、相关文章

      自定义拖放数据:这篇文章是讲述怎么自定义QMimeData数据的,我使用的是其中第二个方法。

      Qt之QAbstractItemView视图项拖拽(一)

      Qt之QAbstractItemView选择无焦点

    如果您觉得文章不错,不妨给个打赏,写作不易,感谢各位的支持。您的支持是我最大的动力,谢谢!!! 

     

      


    很重要--转载声明

    1. 本站文章无特别说明,皆为原创,版权所有,转载时请用链接的方式,给出原文出处。同时写上原作者:朝十晚八 or Twowords
    2. 如要转载,请原文转载,如在转载时修改本文,请事先告知,谢绝在转载时通过修改本文达到有利于转载者的目的。 

  • 相关阅读:
    科普下病菌和病毒
    centos环境下安装docker
    change master to到一个不存在的主库或主库无法连接
    java.lang.outofmemoryerror android
    委托 C#
    将PC端的网站转化成手机端网站需要增加以下这段代码即可,再布局一下界面即可
    combobox联动
    删除dataGridview中选中的一行或多行
    vs2010下如何使【“System.Data.OracleClient.OracleConnection”已过时】 解决办法
    MyEclipse连接SQL Server 2008数据库的操作方法
  • 原文地址:https://www.cnblogs.com/swarmbees/p/6055280.html
Copyright © 2011-2022 走看看