Qt之QAbstractItemView视图项拖拽(二)

36 篇文章 5 订阅
32 篇文章 0 订阅

一、需求说明

上一篇文章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. 最后鼠标释放时,判断如果需要更新拖拽项位置,那么把原有项删除,并构造新的项插入到目标位置
  5.   上边的几个步骤描述都是在mouse系列的回到接口中发生的,再也没有QDrag的事儿啦。当然这个mouse方法中需要做一些鼠标状态维护等。
    

四、代码说明

1、重要的类和上一篇文章中的一样,忘记的小伙伴可以到上一篇文章查看,或者猛戳Qt之QAbstractItemView视图项拖拽(一)

2、下面就直接上代码

a、记录鼠标按下时信息

void DragList::mousePressEvent(QMouseEvent * event)
{
    if (event->button() == Qt::LeftButton)
    {
        m_LeftPress = true;
        startPos = event->pos();
        dragItem = itemAt(event->pos());
    }

    QListWidget::mousePressEvent(event);
}

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

void DragList::mouseMoveEvent(QMouseEvent * event)
{
    QListWidgetItem * item = itemAt(event->pos());
    if (dragItem == nullptr)
    {
        dragItem = itemAt(event->pos());
    }

    if (m_ShotPicture == nullptr)
    {
        InitShotLabel();
    }
    if (m_ShotLine == nullptr)
    {
        InitShotLine();
    }

    QRect rect = visualItemRect(dragItem);
    if (ListItem * hoverWidget = ItemWidget(item))
    {
        QRect hoverRect = visualItemRect(item);
        QPoint pos = hoverWidget->mapFromParent(event->pos());
        if (hoverRect.size().height() / 2 < pos.y())
        {
            m_ShotLine->move(mapToGlobal(QPoint(2, hoverRect.y() + hoverRect.height() + 1)));
        }
        else
        {
            m_ShotLine->move(mapToGlobal(QPoint(2, hoverRect.y() + 1)));
        }
        
        m_ShotLine->setVisible(hoverRect.contains(event->pos()));
    }

    if (ListItem * newWidget = ItemWidget(dragItem))
    {
        m_ShotPicture->move(mapToGlobal(event->pos() - newWidget->mapFromParent(startPos)));
        if (rect.contains(event->pos()) || event->pos().isNull())
        {
            setCursor(Qt::ForbiddenCursor);
        }
        else
        {
            setCursor(Qt::ArrowCursor);
        }
        if (m_ShotPicture->isHidden())
        {
            m_ShotPicture->show();
        }
    }


//    QListWidget::mouseMoveEvent(event);
}

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

void DragList::mouseReleaseEvent(QMouseEvent * event)
{
    if (event->button() == Qt::LeftButton)
    {
        m_LeftPress = false;
        if (m_ShotPicture)
        {
            m_ShotPicture->close();
            m_ShotPicture->deleteLater();
            m_ShotPicture = nullptr;
        }
        if (m_ShotLine)
        {
            m_ShotLine->close();
            m_ShotLine->deleteLater();
            m_ShotLine = nullptr;
        }
        MouseRelease(event);
    }

    setCursor(Qt::ArrowCursor);

    QListWidget::mouseReleaseEvent(event);
}

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

void DragList::InitShotLabel()
{
    m_ShotPicture = new QLabel;
    m_ShotPicture->setWindowOpacity(0.95);
    m_ShotPicture->setWindowFlags(Qt::FramelessWindowHint | Qt::Tool | Qt::WindowStaysOnTopHint);
    m_ShotPicture->setAttribute(Qt::WA_TransparentForMouseEvents, true);

    if (ListItem * oldWidget = ItemWidget(dragItem))
    {
        m_ShotPicture->setPixmap(oldWidget->grab());
        m_ShotPicture->resize(visualItemRect(dragItem).size());
    }
    m_ShotPicture->show();
}

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

void DragList::InitShotLine()
{
    m_ShotLine = new QLabel;
    m_ShotLine->setObjectName(QStringLiteral("ShotLine"));
    m_ShotLine->setWindowFlags(Qt::FramelessWindowHint | Qt::Tool | Qt::WindowStaysOnTopHint);
    m_ShotLine->setAttribute(Qt::WA_TransparentForMouseEvents, true);
    m_ShotLine->setStyleSheet("QLabel#ShotLine{background:green;}");//用图片代替
    
    if (ListItem * oldWidget = ItemWidget(dragItem))
    {
    //    m_ShotLine->setPixmap(oldWidget->grab());
        m_ShotLine->resize(visualItemRect(dragItem).size().width(), 2);
    }
    m_ShotLine->show();
}

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

void DragList::MouseRelease(QMouseEvent * event)
{
    QListWidgetItem * item = itemAt(event->pos()); 
    if (item == nullptr || item == dragItem)
    {
        return;
    }

    int insertPos = row(item);
    if (ListItem * oldWidget = ItemWidget(item))
    {
        QPoint pos = oldWidget->mapFromParent(event->pos());
        if (oldWidget->size().height() / 2 < pos.y())
        {
            insertPos += 1;
        }
    }

    if (dragItem)
    {
        if (ListItem * oldWidget = ItemWidget(dragItem))
        {
            QListWidgetItem * newItem = new QListWidgetItem;
            ListItem * itemWidget = new ListItem;
            itemWidget->SetData(oldWidget->GetData());

            insertItem(insertPos, newItem);
            setItemWidget(newItem, itemWidget);

            setCurrentItem(newItem);

            oldWidget->deleteLater();
        }

        dragItem = takeItem(row(dragItem));
        if (dragItem)
        {
            delete dragItem;
            dragItem = nullptr;
        }
    }
}

五、下载链接

Qt之QAbstractItemView视图项拖拽2

六、相关文章

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

Qt之QAbstractItemView视图项拖拽(一)

Qt之QAbstractItemView选择无焦点


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




很重要–转载声明

  1. 本站文章无特别说明,皆为原创,版权所有,转载时请用链接的方式,给出原文出处。同时写上原作者:朝十晚八 or Twowords

  2. 如要转载,请原文转载,如在转载时修改本文,请事先告知,谢绝在转载时通过修改本文达到有利于转载者的目的。


  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值