2017-09-13 49 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