2017-09-13 70 views
2

TL寿命; DR
如何正确地传递信息,包装成一个QObject以QML中的信号可能与高频发射,减少开销,保证了对象/引用至少执行连接的插槽?管理C++的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

如果您需要m_lastInformation始终存在并且它的信息应该总是逐个处理 - >在您的C++ func中使用QMutex和QMutexLocker。如果m_lastInformation的信息应该更新而没有carrieng,如果旧实例已经处理 - >在C++中使用QSharedPointer for m_lastInformation – Xplatforms

回答

4

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

如果鼠标区域回收了相同的事件对象,它不会在随后的点击中失效。

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

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

+0

* downvote不是我的* - 因此,建议将值存储在发送信号的对象中,或者它的PIMPL,然后创建一个简单的'Q_GADGET',我传入的信号可以访问相同的数据。现在我可能会摧毁这个'Q_GADGET',只要我喜欢它(例如底层的数据改变)? – derM

+3

两者都可以为你工作,这取决于你需要完成什么。如果信号发送者是持久的,那么如果它存储了这些东西,它将非常干净和高效,除了因为你已经有一个引用它来建立连接,你甚至不需要在信号中传递任何额外的东西,就像你可以简单地使用发件人引用来检索该信息。当您需要通过“伪”引用有效地传递大对象时,gadget + pimpl非常有用,同时仍然避免了'QObject'的开销,同时保留了属性和可调用函数的基本元。 – dtech