TL; DR
如何在可能以高频率发出的信号中正确传递信息,将QObject
包装为QML,从而减少开销,确保对象/引用至少超过连接插槽的执行?
我有一个C ++ QObject注册为QML类型。该对象有一些信号
void someSignal(InformationQObject* someInformation)
其中我没有传递单独参数中的所有信息,而是传递给一个对象 - 类似于找到的信号,例如在MouseArea
中,例如信号
void clicked(QQuickMouseEvent *mouse)
现在我想知道这个someInformation
的正确生命周期管理。
到目前为止,在我的目标中,我有一个成员:
InformationQObject* m_lastInformation
并发送我使用的信号:
void sendMySignal(/* possible params */)
{
delete m_lastInformation
m_lastInformation = new InformationQObject(/* right params here */)
emit someSignal(m_lastInformation)
}
现在这似乎不对。
理由:如果你看一下QQuickMouseArea
的实现,他们会采用不同的方式。看起来他们并没有为每个事件创建一个新对象,而是回收现有事件。我发现很难跟踪他们的所有来源,但我认为他们的一个文件中的这个评论给出了一个很好的理由:
QQuickPointerEvent用作存储相关数据的长期对象 来自指点设备的事件,例如鼠标,触摸或平板电脑事件, 在活动期间。它还提供可在以后使用的属性 将事件暴露给QML,与QQuickMouseEvent相同, QQuickTouchPoint,QQuickKeyEvent等等,因为只有一个事件可以 一次交付,这个班级实际上是一个单身人士。我们不担心 关于QObject开销,因为实例是长寿的:我们没有 为每个事件动态创建和销毁此类型的对象。
但这是让我看到它变得复杂的地方,他们是如何做到的。此评论与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.
}
}
所以必定会有一些魔法发生,我不明白。
答案 0 :(得分:5)
你正在打开一堆蠕虫。 QML lifetime management is broken in above-trivial scenarios,API并没有真正为您提供一种有意义的方式来解决这个问题。我的解决方案是将所有权设置为CPP并手动管理对象的生命周期。原始我知道,但唯一的解决方案是避免删除仍在使用的对象和实际的硬崩溃。
如果鼠标区域回收了相同的事件对象,则在后续点击时它不会变为无效。
如果您的代码反映了您的实际使用情况,我建议您只复制单个事件属性,而不是尝试将实际事件存储在专用属性中,或者作为JS对象存储,如果您想避免开销并且不要; t需要通知。我倾向于使用数组,并依赖更快的索引访问。
我可以推荐的另一个解决方案是带有PIMPL的Q_GADGET
- 小工具受设计限制,因此它们不能作为指针传递,并且它们总是按值复制,但是您可以让实际对象只包含一个指向较重的数据实现的指针,仅用作访问器和接口以从QML访问数据。这样你就可以重用数据,实际的对象值可以忽略不计,因为它基本上只是一个指针而且不涉及任何动态内存分配。您还可以将实际数据公开为不透明对象,以便将其复制到其他小工具并使用ref count来管理数据生命周期。