美文网首页
实现拖入文件到QtTreePropertyBrowser中的属性

实现拖入文件到QtTreePropertyBrowser中的属性

作者: 瑶琴频曲羽衣魂 | 来源:发表于2022-11-22 15:25 被阅读0次

    目录

    环境

    Windows 10
    Visual Studio 2017/2019 Professional/Community
    Qt 5.15.1
    Qt Creator 4.11.0

    需求

    现在需要拖入文件到一个String类型的属性,能自动转换成路径的快捷功能

    实现效果

    拖入文件到QtTreePropertyBrowser中的属性转成字符串.gif

    实现原理

    由于源码中缺乏通过QPoint获取QtProperty/QtBrowserItem/QModelIndex的功能,关键部分是要实现通过放下文件一瞬间的QPoint找到对应的QtProperty。
    QtTreePropertyBrowser分为标题头和属性表两部分。属性表由源码自定义的QTreeWidget作为表现(如下代码)。

    class QtPropertyEditorView : public QTreeWidget
    {
        //...
    }
    class QtTreePropertyBrowserPrivate
    {
        //...
    private:
        QtPropertyEditorView *m_treeWidget;
        //...
    };
    

    注意,该版本中,调用QTreeWidgetItem* QTreeWidget::itemAt(QPoint)这个函数,无法获取到正确的结果。

    实现

    源码改动

    QtTreePropertyBrowser

    获取内置的QTreeWidget

    QTreeWidget* QtTreePropertyBrowser::treeWidget() const
    {
        return d_ptr->treeWidget();
    }
    

    从获取到的QTreeWidgetItem,转换成QtBrowserItem,进而取到QtProperty

    QtBrowserItem * QtTreePropertyBrowser::browserItem(QTreeWidgetItem* twi) const
    {
        return d_ptr->m_itemToIndex[twi];
    }
    

    关键代码

    封装两个函数:

    使用BFS遍历各个QTreeWidgetItem,使用QRect QTreeWidget::visualItemRect(QTreeWidgetItem*)获取改子项的UI范围,判断子项是否包含posLocal。posLocal是相对于QTreeWidget的位置,下方有进一步说明。

    QTreeWidgetItem* treeWidgetItemAtPoint(const QTreeWidget* tw, const QPoint& posLocal)
    {
        QQueue<QTreeWidgetItem*> bfsQueue;
        int count = tw->topLevelItemCount();
        for (int i = 0; i < count; i++)
        {
            QTreeWidgetItem* twi = tw->topLevelItem(i);
            bfsQueue.push_back(twi);
        }
        QTreeWidgetItem* target = nullptr;
        while (!bfsQueue.empty())
        {
            QTreeWidgetItem* twi = bfsQueue.takeFirst();
            count = twi->childCount();
            for (int i = 0; i < count; i++)
            {
                QTreeWidgetItem* twiChild = twi->child(i);
                bfsQueue.push_back(twiChild);
            }
            QRect rect = tw->visualItemRect(twi);
            if (!rect.contains(posLocal))
            {
                continue;
            }
            target = twi;
            break;
        }
        return target;
    }
    

    这里的pos是相对于QtTreePropertyBrowser的位置,接入您的项目时,根据实际情况调整pos的值。
    可优先用tpb->geometry()判断是否在UI范围内。
    下一步重要的是,pos.y是否要减去HeaderView的高度。
    然后调用上述的treeWidgetItemAtPoint,获取QTreeWidgetItem。
    最后通过在源码新增的函数获取QtBrowserItem,进而获取QtProperty。

    QtProperty* propertyAtPoint(const QtTreePropertyBrowser* tpb, const QPoint& pos)
    {
        QTreeWidget* tw = tpb->treeWidget();
        QRect rect = tpb->geometry();
        if (!rect.contains(pos))
        {
            return nullptr;
        }
        QPoint posBody = pos;
        if (tpb->isHeaderVisible())
        {
            //pos减去Header高度
            posBody.setY(pos.y() - hv->height());
        }
        QTreeWidgetItem* twi = treeWidgetItemAtPoint(tw, posBody);
        if (!twi)
        {
            return nullptr;
        }
        QtBrowserItem* bi = tpb->browserItem(twi);
        if (!bi)
        {
            return nullptr;
        }
        return bi->property();
    }
    

    业务代码

    开始,设置QtTreePropertyBrowser接收放置文件事件(同样可在Qt Creator中设置)。
    同时重写dragEnterEventdropEvent,来接收文件。
    在dropEvent中,直接使用QCursor::pos()与QTreeWidget的QWidget::mapFromGlobal(posCursor),传入我们上述封装函数的相对于QtTreePropertyBrowser的位置。

    最后的vpm->propertyType(prop) == QVariant::String,可根据自身项目,判断不同的类型(含自定义类型)来处理不同逻辑

    XXX::XXX(/*...*/) :
        //...
    {
        //...
        QtTreePropertyBrowser* tpb = /*...*/;
        tpb->setAcceptDrops(true);
        //...
    }
    
    void XXX::dragEnterEvent(QDragEnterEvent *event)
    {
        if (!event->mimeData()->hasUrls())
        {
            return;
        }
        event->acceptProposedAction();
    }
    
    void XXX::dropEvent(QDropEvent *event)
    {
        QList<QUrl> listUrl = event->mimeData()->urls();
        if (listUrl.empty())
        {
            return;
        }
        QUrl url = listUrl[0];
        QtTreePropertyBrowser* tpb = /*...*/;
        QTreeWidget* tw = tpb->treeWidget();
        QPoint posCursor = QCursor::pos();
        QPoint posTwLocal = tw->mapFromGlobal(posCursor);
        QtProperty* prop = propertyAtPoint(tpb, posTwLocal);
        if (!prop)
        {
            return;
        }
        QtVariantProperty* vp = static_cast<QtVariantProperty*>(prop);
        QtVariantPropertyManager* vpm = /*...*/;
        if (vpm->propertyType(prop) == QVariant::String)
        {
            if (vp)
            {
                vp->setValue(url.toLocalFile());
            }
        }
    }
    

    相关文章

      网友评论

          本文标题:实现拖入文件到QtTreePropertyBrowser中的属性

          本文链接:https://www.haomeiwen.com/subject/kuknxdtx.html