管理在信号

时间:2017-09-13 09:06:21

标签: c++ qt qml qt5 qtquick2

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.
    }
}

所以必定会有一些魔法发生,我不明白。

1 个答案:

答案 0 :(得分:5)

你正在打开一堆蠕虫。 QML lifetime management is broken in above-trivial scenarios,API并没有真正为您提供一种有意义的方式来解决这个问题。我的解决方案是将所有权设置为CPP并手动管理对象的生命周期。原始我知道,但唯一的解决方案是避免删除仍在使用的对象和实际的硬崩溃。

如果鼠标区域回收了相同的事件对象,则在后续点击时它不会变为无效。

如果您的代码反映了您的实际使用情况,我建议您只复制单个事件属性,而不是尝试将实际事件存储在专用属性中,或者作为JS对象存储,如果您想避免开销并且不要; t需要通知。我倾向于使用数组,并依赖更快的索引访问。

我可以推荐的另一个解决方案是带有PIMPL的Q_GADGET - 小工具受设计限制,因此它们不能作为指针传递,并且它们总是按值复制,但是您可以让实际对象只包含一个指向较重的数据实现的指针,仅用作访问器和接口以从QML访问数据。这样你就可以重用数据,实际的对象值可以忽略不计,因为它基本上只是一个指针而且不涉及任何动态内存分配。您还可以将实际数据公开为不透明对象,以便将其复制到其他小工具并使用ref count来管理数据生命周期。