首页 > 其他分享 >QTreeView中item节点任意拖拽移动,添加,删除与自绘指示器

QTreeView中item节点任意拖拽移动,添加,删除与自绘指示器

时间:2024-05-24 21:26:04浏览次数:26  
标签:10 自绘 QTreeView top QPoint item rect 拖拽 painter

文章目录

效果图

在这里插入图片描述


主要功能点

  1. 节点自由拖拽移动

  2. 自绘树的指示器

  3. 可拖拽添加节点


概要

  • 整体还是对于model-view这一套的使用,左侧的实现可看我的这篇文章,本文具体讲讲这个树QTreeView的拖拽与自绘指示器。

  • 关于树节点的增删改查,我就不解释了,文末我也会贴出源码仓库,自己去看。若觉得项目复杂,可以直接看QT的demo,
    在这里插入图片描述

  • 若是你想了解拖拽,我推荐你看QT的这个demo,方便你快速搞定。
    在这里插入图片描述


遇到的问题

  1. 当外部数据拖入到树上时,鼠标样式为禁止状态,不可放下。
  • setAcceptDrops(true);设置支持放置
  1. 当外部数据拖入到树上时,没有触发指示器
  • 这个问题其实很麻烦,查了很多资料才知道,树的指示器要是树中模型已存好的数据才会触发,像这种外部拖进来的不会有,这种时候只能通过自绘实现,下面会详细说明,也是本文的重点。
  1. 如何判断树指示器的位置的
  • 这个是树中只带的类DropIndicatorPosition决定的,你无法改变

指示器

  • QTreeView里只需要使用setStyle函数设置继承于,QProxyStyle的类就行,QProxyStyle中需要重写drawPrimitive函数。

函数代码如下

void ControlViewStyle::drawPrimitive(PrimitiveElement element, const QStyleOption *option, QPainter *painter, const QWidget *widget) const
{
    if (element == QStyle::PE_IndicatorItemViewItemDrop && !option->rect.isNull())
    {
        QRect rect = option->rect;
        QPen pen;
        pen.setColor(QColor(qRgb(135, 206, 235)));
        pen.setWidth(2);
        painter->setPen(pen);
        painter->setRenderHint(QPainter::Antialiasing);
        if (option->rect.height() == 0)
        {
            painter->drawEllipse(QPoint(10, option->rect.top()), 4, 4);
            painter->drawLine(QPoint(10, rect.top()), QPoint(widget->width() - 10, rect.top()));
        }
        else
        {
            rect.setLeft(5);
            rect.setRight(widget->width() - 5);
            painter->drawRect(rect);
        }

        return;
    }
    QProxyStyle::drawPrimitive(element, option, painter, widget);
}
  • 设置完成后,处于树内的节点任意拖拽是会出现自绘的指示器了。但是从树外拖入的数据,指示器并不会出现。这个时候就需要通过树中paintEvent实现自绘了。在拖拽move时可以通过DropIndicatorPosition得到当前所在位置,以及dragMoveEvent处理得到的数据是树内还是树外(防止多次绘制),不断的update,从而达到自绘效果。
    函数如下
void ControlDialogTreeView::paintEvent(QPaintEvent *event)
{
    QTreeView::paintEvent(event);

    if (m_hoveredIndex.isValid() && !m_isMyselfDrop)
    {
        QPainter painter(viewport());
        QRect rect = visualRect(m_hoveredIndex);
        QRect rowRect = getRowVisualRect(m_hoveredIndex);
        QPen pen;
        pen.setColor(QColor(qRgb(135, 206, 235)));
        pen.setWidth(2);
        painter.setPen(pen);
        painter.setRenderHint(QPainter::Antialiasing);

        DropIndicatorPosition dropindicationPos = dropIndicatorPosition();
        switch (dropindicationPos)
        {
        case QAbstractItemView::AboveItem:
        {
            painter.drawEllipse(QPoint(10, rowRect.top()), 4, 4);
            painter.drawLine(QPoint(10, rect.top()), QPoint(rowRect.width() + 10, rect.top()));
        }
        break;
        case QAbstractItemView::BelowItem:
        {
            painter.drawEllipse(QPoint(10, rowRect.top()), 4, 4);
            painter.drawLine(QPoint(10, rect.top()), QPoint(rowRect.width() + 10, rect.top()));
        }
        break;
        case QAbstractItemView::OnItem:
        {
            rect.setLeft(5);
            rect.setRight(rowRect.width() + 5);
            painter.drawRect(rect);
        }
        break;
        case QAbstractItemView::OnViewport:
            qDebug() << "*****OnViewport";
            break;
        }
    }
}
  • 移动
void ControlDialogTreeView::dragMoveEvent(QDragMoveEvent *event)
{
    QTreeView::dragMoveEvent(event);
    auto data = event->mimeData();
    if (!data->hasFormat(GlobalDefinition::controlDialogMimeType))
    {
        m_isMyselfDrop = false;
    }
    QModelIndex index = indexAt(event->pos());
    if (index.isValid())
    {
        m_hoveredIndex = index;
        update();
    }
    else
    {
        m_hoveredIndex = QModelIndex();
    }
    event->accept();
}


拖拽

  • 拖拽的话还是推荐看QT的demo,那些示例很明了。

  • 简单说一下,你的拖拽若是使用了Model-view这套设计思想,那么数据的关键就在Model中的mimeData函数中,mimeTypes函数设置支持那些数据的放置,supportedDropActions支持那些操作类型,以及view中各种事件的处理。简单点的,像上面我推荐的demo,不使用Model-view。直接在mousePressEvent就可以实现,关键在于你的把你的数据存到QMimeData,然后在drop的时候能解析出来。拖拽的代码太多了,我就不贴出来了,感兴趣的可以自己把仓库拉下来。


总结

  • 知识理应共享,源码在此

  • 写这个案例遇到的问题其实很多,当然也让自己学到了挺多,对拖拽这套理解更深了点

标签:10,自绘,QTreeView,top,QPoint,item,rect,拖拽,painter
From: https://blog.csdn.net/weixin_49065061/article/details/139063945

相关文章

  • ListBox中的ItemTemplate
    //ListBox中的ItemTemplate用于定义每个单独项的外观,允许你自定义ListBox中显示的每个数据项的样式和布局。//可以在ItemTemplate中放置控件、数据绑定和其他布局结构,以便在ListBox中呈现每个数据项时具有一致的外观。ItemTemplate的使用使得ListBox能够根据需要对每个项目进行......
  • Bridging Language and Items for Retrieval and Recommendation
    目录概BLaIR代码HouY.,LiJ.,HeZ.,YanA.,ChenX.,andMcAuleyJ.Bridginglanguageanditemsforretrievalandrecommendation.2024.概本文提出了一种利用对比损失训练的预训练模型,能够把握数据集中的交互信息.BLaIRBLaIR的思想很简单如上图所示,输入......
  • currentTuningFileInfoRef.current = useMemo(() => { return tuningFileOptionsMemo?
    在React中,useMemo和useEffect都是Hooks,但它们各自有不同的用途和适用场景。上述代码片段使用了useMemo来memoize(记忆化)一个计算结果,确保只要依赖项(tuningFileOptionsMemo和currentTuningFileId)不变,返回的引用也不会改变。这样做可以避免在每次渲染时都进行查找操作,从而提......
  • Sitecore 设置 SelectItems 最大长度问题
    添加一个configpatch文件即可,然后放在App_Config下,内容如下:sitecore默认value是100。<?xmlversion="1.0"encoding="utf-8"?><configurationxmlns:patch="http://www.sitecore.net/xmlconfig/"xmlns:role="http://www.sitecore.n......
  • WPF ListBox acts image container, ItemTemplate,DataTemplate,
    <Windowx:Class="WpfApp100.MainWindow"xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"xmlns:d="http://schemas.microsoft......
  • [Javascript] Find Items from the end of the JavaScript Array using at, findLast
    Findingelementsstartingfromtheendofanarrayhasgottenaloteasierwiththeintroductionofthe at, findLast,and findLastIndex methods!With at younolongerneedtoremembertoaccesstheendofthearraylike array[array.length-1] trick.......
  • QStandardItemModel遍历查找搜索关键字
    (1)findItems查找内容筛选项,只能查找显示的文字中是否包含该文字,但是QList<QStandardItem*>findItems(constQString&text,Qt::MatchFlagsflags=Qt::MatchExactly,intcolumn=0)const;(2)mat......
  • QStandardItemModel 遍历勾选的项
    QStandardItemModel遍历勾选的项rowCount()不能传入 m_model->index(0,0)根节点,无法获取行数;不传,或者传入一个空QModelIndex对象,可以获取到第一级节点的数量;QMap<QString,QVariantMap>mapSelectVideo;introotRowCount=m_model->rowCount();for(inti=0;i<ro......
  • UITabBarController点击UITabBarItem 禁止跳转 iOS
    写在下面类里无效,切记classCJZFTabBarViewController:UITabBarController{} 需要写在appdelegate或者基类里,可以拦截tabbaritem是否被选中。选中了后,才会走  didSelect代理方法。 @interfaceBaseViewController()<UITabBarControllerDelegate>@end//判......
  • 前后端分离,提供蜘蛛爬行最简单方案,创建sitemap xml
    2024年5月13日11:36:01现在很多项目是vuereactangular开发的,但是百度爬虫对这样的项目支持不好,很多时候回去采用一些服务器端渲染(SSR)和静态站点生成(SSG),当然有些框架支持ssr和ssg效果不好,还有些想不不破坏项目自身的提前下的方案呢?很多年前接手一个angularjs的项目,但是......