环境: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表示式。
如果还存在异常,那一定是指针问题。