QWidget在嵌入qml窗口时的资源管理问题的解决

环境:Qt 5.12 MinGW

情况介绍:   

    当我用loader加载窗口,然后在窗口加载一个QWidget的时候,我以为直接用Loader释放就一切OK,当异常发生时,我也以为就是一个简单的killwin的过程,但没想到花了超过一个下午的时间解决,后面还是新建一个测试工程详细测试解决的。 

一、QWidget嵌入qml

现在其实网上很多这种教程,无非就是运用c++的多态性性,实现类型的转换;我这里用的是QWidget的WinId转本地窗口,完后调用windowHandle()部分;当然,也可以直接调用各个平台的API去获取、killwin,这样显然更快,但也麻烦。.//注意setparent后需要重新show

部分代码参考:

    widget=new Widget;
    widget->winId();

    QWindow*temp=widget->windowHandle();
    if(temp)qDebug()<<"sucessful";
    else {qDebug()<<"unsucessful";return;}
    temp->setParent(w);
    widget->move(100,100);
widget.show();
//注意lambda表达式不要对临时变量使用引用访问,即使是指针也不行
//测试qml资源是否释放
    connect(w,&QWindow::destroyed,[=](QObject *obj){
        qDebug()<<"wind destroy";
    });
//发出主动释放信号释放QWidget
    connect(this,&MyModel::dd,[=](){
         qDebug()<<"dd";
//注意断开信号 因为信号槽接收者默认是this,信号存在则会调用未知指针
this->disconnect(SIGNAL(dd()));
        widget->deleteLater();
    });

二、释放窗口资源 

   loader直接释放资源,但释放的是qml的资源,为什么呢,我猜测还是和JS的值复制原则的原因,它只能复制指针对象,只能操作指针对象,但不能对常规变量进行直接操作,而常规变量是可以包含指针对象的,所以QML是不能直接释放QWidget的资源的,需要手动去释放。

  但还是有细节,那就是先killwin在用loader释放,这个细节很关键。

部分测试参考:

   {
send()//呼叫QWidget去kill itself
            console.log("??")
            loader.source = ""
}

  可以看到完全符合预期,先是widget调用deleteLater,然后在用loader释放资源,在接下来回到widget所在的事件圈删除widget,最终在回到loader的删除调用所在的事件圈删除qmlwin。从这里看出来了,loader的释放方式是和deleteLater是一致的。

  当然,也可以用destroy,delete这种直接调用方式,这样应该要快一些,但deletelater是线程安全的。

笔记:loader的释放代码要在widget释放代码之后;槽通信中不能对临时指针使用按引用访问的lambda表示式。

如果还存在异常,那一定是指针问题。

猜你喜欢

转载自blog.csdn.net/qq_40032304/article/details/106987928