通过C++将dll中的qml动态加载到指定qml中

好吧,看标题有点绕口。本文要讲的也不是qtquick的插件的内容。不过也不复杂,就一层窗户纸。可能太简单了,反而很少这方面的资料。

现实中经常需要根据需要(譬如不同的配置文件),装载不同的dll,然后将dll中的qml显示在UI上。譬如说,一个QGuiApplication应用appA作为启动程序,还有依照配置文件需要调用的动态链接库dllB.当然,也可以通过更改配置文件装载不同的dllC,dllD等。

关于appA,vs2019+qt扩展,新建的工程大概就是这样的:

    QGuiApplication app(argc, argv);

    QQmlApplicationEngine engine;
    engine.load(QUrl(QStringLiteral("qrc:/qt/qml/qwork/main.qml")));
    ....

main.qml里面定义个Rectangle:

    Rectangle
    {
        objectName: "rect_main"
        anchors.fill:parent
    }

dllB里面建立了一个page_start.qml.当然,以后也许会加载其他的什么dll里面的qml。但是不希望每次都修改appA了。希望把page_start.qml添加到rect_main里面。怎么做呢?大概的思路基于以下几点:

1  QLibrary提供了动态调用dll的方法;

2 C++要操作两个UI控件,直接的想法无非就是先建立两个控件的实体,然后获得两者的指针。对于已有的实体,通过findChild找到,对于需要新建的,通过QQmlComponent的create方法,当然,别忘了把engine的指针也传过去供QQmlComponent使用。

3 qml本质上就是个脚本,通过QQmlComponent的create或者其他的一些方法建立一个与之对应的QQuickItem的实体,这个QQuickItem的实体本质可以理解为发芽自engine的树状结构。通过setParentItem告诉当前的树枝或者树叶,它的上一级是哪一号,这样就可以把它拼接到这棵树上。

4 只要接口规则不变,就可以随意替换。

建立一个类,最简单的如下:

class c_interface: public QObject
{
public:
    Q_INVOKABLE virtual bool addQmltoParent(QObject* p_parent, QQmlApplicationEngine* p_engine) = 0;
}

在dllB中,定义一个class dllPage继承自c_interface。当然,后续我们也可以建立其他的dll,只要建立一个继承自c_interface的类。

于是

class Q_DECL_EXPORT dllPage : public c_interface
{
public:
    explicit dllPage(QObject* parent = nullptr);
    ~dllPage();
    Q_INVOKABLE bool addQmltoParent(QObject* p_parent, QQmlApplicationEngine* p_engine)     override;
private:

    QQmlComponent* m_qml_component;
    QQuickItem* m_qml_item;
}


Q_INVOKABLE bool dllPage::addQmltoParent(QObject* p_parent, QQmlApplicationEngine* p_engine)
{
	m_qml_component = new QQmlComponent(p_engine, QUrl::fromLocalFile("page_start.qml"));
	m_qml_item = qobject_cast<QQuickItem*>(m_qml_component->create());
    if(m_qml_item != nullptr)
    {

        m_qml_item->setProperty("anchors.fill", "parent");
	    m_qml_item->setParentItem((QQuickItem*)p_parent);
        return true;
    }
    return false;
}

不过这还没完,你还得定义一个函数供QLibrary去resolve:

extern "C"
{
	Q_DECL_EXPORT c_interface* createNewInstance();

}

于是,在appA里面,你就可以这样:

    typedef c_interface* (*createNewInstanceFunc)(void);
    QGuiApplication app(argc, argv);

    QQmlApplicationEngine engine;
    engine.load(QUrl(QStringLiteral("qrc:/qt/qml/qwork/main.qml")));
    QObjectList obj_lst = engine.rootObjects();
    if (obj_lst.isEmpty())
        return -1;

    QLibrary lib("dllB.dll");
    if(lib.load())
    {
        auto main = obj_lst[0]->findChild<QObject*>("rect_main");
        if(main != nullptr)
        {
            createNewInstanceFunc func = (createNewInstanceFunc)lib.resolve("createNewInstance");
            if (func != nullptr)
            {
                
                c_interface* ins = func();
                if (ins != nullptr)
                {
                    ins->addQmltoParent(main, &engine);
                }
            }
        }
    }

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值