2016-11-21 50 views
1

我是Qt的新手。我有一個工作線程,它是一個std::thread。工作線程函數不斷地在循環中獲取一些數據。數據的大小經常在QML UI上的Text元素上更新。我有一個監聽器回調,它只是一個std::function,它從thread's function被調用。它向我發送回調,我根據該回調更新了Text元素QML。我使用signal slot機制更新它。從工作線程發出Qt ::信號默認情況下會在主線程上更新UI?

以下是QML : Text元件:

Text { 
    id: mytext 
    objectName: "mytextobject" 

    function slotUpdateData(someValue){ 
    mytext = someValue 
    } 
} 

SignalUpdateDataslotUpdateData駐留上QML側連接。每次我從std::thread,I emit SignalUpdateData獲取數據事件回調時,都會更新QML Text element,UI

void CallBackReceivedFromWorkerThread(float someValue) { 
    emit SignalUpdateData(someValue) 
} 

以下是我如何完成主機連接C++ signalQML slot

QObject::connect(this, SIGNAL(SignalUpdateData(QVariant)), myTextItemQObject, SLOT(slotUpdateData(QVariant))); 

而這一切工作正常。沒有崩潰,鎖定,什麼都沒有。

根據我的理解,由於工作線程的函數正在觸發回調,執行控制在收到回調時位於工作線程上。所以在做emit SignalUpdateData(someValue)時,我們仍然在工作線程上。 據我在android & java我以前的經驗知道,我們不能從應用程序的main thread以外的任何地方更新UI。

那麼,這是如何工作的? emit SignalUpdateData(someValue)是否打電話給main UI thread's event loop?儘管我從worker thread撥打電話,Qt仍然在main thread上更改用戶界面?如果我的方法很好,那麼它是否會影響性能?最好的建議是什麼?

我想很肯定這個&不只是幸運的做到這一點。我是否也應該使用Qt::Connection_enum以獲得最佳方法?

+1

據我所知(可能是錯誤的),一切QML發生在主/ gui線程上。 –

回答

7

您正在利用Qt的方式!而且你偶然碰到它:這是一個體面設計的標誌 - 它「正常工作」。爲你的萬歲,萬歲的Qt :)

它的工作原理是因爲Qt是專門爲使它工作而設計的,而且你正在使用默認的自動連接,其存在的理由是在這種情況下幫助你。所以你碰巧做的都是正確的:不做任何改變!

當您發出信號時,Qt會獲取相關的源和目標對象互斥,並將接收對象的thread()QThread::currentThread()進行比較。如果它們是相同的,則立即調用插槽/仿函數:它發生在信號的主體中,所以在信號返回之前調用該插槽。這是安全的,因爲目標對象的使用來自其thread(),因爲它是安全的。

如果target->thread() != QThread::currentThread(),則QMetaCallEvent排隊到目標對象。該事件包含(等價的)插槽方法指針和插槽傳遞的任何參數的副本。 QObject::event實現處理事件並執行呼叫。目標對象線程的事件循環位於調用堆棧上,因爲它的工作是將排隊的事件傳遞給對象。以上是Qt::AutoConnection的含義。如果您使用Qt::QueuedConnection,則無論線程是什麼,第二種情況都適用。如果您使用Qt::DirectConnection,則無論如何,第一種情況都適用。

我的猜測是,對於SO中Qt相關問題中非自動連接類型使用的95%以上是不必要的,並且是由於缺乏理解和訴諸相當於魔法的咒語。

+0

您是否還可以指出這些東西在Qt源代碼中的實現? – Paul

+0

@Paul它大部分都在['QObject'](https://code.woboq.org/qt5/qtbase/src/corelib/kernel/)的實現中,當然它與元數據系統合作。 –

+1

http://code.qt.io/cgit/qt/qtbase.git/tree/src/corelib/kernel/qobject.cpp#n3690 – BaCaRoZzo

相關問題