der*_*erM 3 c++ qt qml qt5 qtquick2
TL; DR
如何正确传递信息,QObject将QML 包装成可能以高频率发出的信号,减少开销,确保对象/引用至少超过连接插槽的执行?
我有一个C++ QObject注册为QML类型.这个对象有一些信号
void someSignal(InformationQObject* someInformation)
Run Code Online (Sandbox Code Playgroud)
其中我没有在单独的参数中传递所有信息但是在一个对象中 - 类似于在例如信号中找到MouseArea的信号
void clicked(QQuickMouseEvent *mouse)
Run Code Online (Sandbox Code Playgroud)
现在我想知道正确的终身管理someInformation.
到目前为止,在我的目标中,我有一个成员:
InformationQObject* m_lastInformation
Run Code Online (Sandbox Code Playgroud)
并发送我使用的信号:
void sendMySignal(/* possible params */)
{
delete m_lastInformation
m_lastInformation = new InformationQObject(/* right params here */)
emit someSignal(m_lastInformation)
}
Run Code Online (Sandbox Code Playgroud)
现在这似乎是错的.
理由:如果你看一下QQuickMouseArea它们的执行情况,就会采用不同的方式.看起来他们并没有为每个事件创建一个新对象,而是回收现有事件.我发现很难找到他们的所有来源,但我认为他们的一个文件中的这个评论给出了一个很好的理由:
QQuickPointerEvent用作长期存在的对象,用于在事件传递期间存储与指点设备(例如鼠标,触摸或平板电脑事件)中的事件相关的数据.它还提供了稍后可用于将事件暴露给QML的属性,与QQuickMouseEvent,QQuickTouchPoint,QQuickKeyEvent等相同.由于一次只能传递一个事件,因此该类实际上是单例.我们不担心QObject开销,因为实例是长期的:我们不会为每个事件动态创建和销毁此类型的对象.
但这是让我看到它变得复杂的地方,他们是如何做到的.这个评论是关于a QQuickPointerEvent.有一个QQuickPointerMouseEvent.在他们的信号中他们通过了QQuickMouseEvent*
后者是指向其中一个成员的指针QQuickMouseEvent quickMouseEvent.
在某些时候,不知何故,这个指针在QML中变得无效
MouseArea {
anchors.fill: parent
property var firstEvent
onClicked: {
if (firstEvent === undefined) firstEvent = mouse
console.log(mouse.x, mouse.y)
console.log(firstEvent.x, firstEvent.y) // -> TypeError on second and consecutive clicks.
}
}
Run Code Online (Sandbox Code Playgroud)
所以必定会有一些神奇的事情发生,我不明白.
你正在打开一堆蠕虫.QML生命周期管理在上述方案中被打破,并且API并没有真正为您提供一种有意义的方法来解决这个问题.我的解决方案是将所有权设置为CPP并手动管理对象的生命周期.原始我知道,但唯一的解决方案是避免删除仍在使用的对象和实际的硬崩溃.
如果鼠标区域循环使用相同的事件对象,则在后续单击时不会变为无效.
如果您的代码反映了您的实际使用情况,我建议您只复制单个事件属性,而不是尝试将实际事件存储在专用属性中,或者作为JS对象存储,如果您想避免开销并且不需要通知.我倾向于使用数组,并依赖更快的索引访问.
我建议的另一个解决方案是Q_GADGET使用PIMPL - 小工具受设计限制,因此它们不能作为指针传递,并且它们总是按值复制,但是您可以让实际对象只包含指向较重数据实现的指针,并且仅用作访问器和接口以从QML访问数据.这样你就可以重用数据,实际的对象值可以忽略不计,因为它基本上只是一个指针而且不涉及任何动态内存分配.您还可以将实际数据公开为不透明对象,以便将其复制到其他小工具并使用ref count来管理数据生命周期.