QT中的信號與事件碎税,多線程

相同點

  • 目的都是為了解決對象間通信的問題。
  • 事件發(fā)生或信號發(fā)射時會有相應的處理函數(shù)啃匿。

不同之處

  1. 返回值

    • 事件有返回值蛔外,并且有意義蛆楞,我們要根據(jù)這個返回值來確定是否還要繼續(xù)事件的處理,比如在QT中夹厌,事件處理函數(shù)如果返回true豹爹,則這個事件處理 已完成,QApplication會接著處理下一個事件矛纹,而如果返回false臂聋,那么事件分派函數(shù)會繼續(xù)向上尋找下一個可以處理該事件的注冊方法。
    • 信號處理函數(shù)沒有返回值或南。
  2. 響應時優(yōu)先級

    • 在QT中孩等,事件使用了一個事件隊列來維護,如果事件的處理中又產(chǎn)生了新的事件采够,那么新的事件會加入到隊列尾肄方,直到當前事件處理完畢后, QApplication再去隊列頭取下一個事件來處理蹬癌。
    • 信號類似于硬件中的中斷权她,當一個信號產(chǎn)生后,他上面注冊的所有槽都會被按順序立即執(zhí)行逝薪。相應的隅要,產(chǎn)生遞歸調(diào)用的問題,比如在某個信號處理槽中又產(chǎn)生了一個信號董济,當前處理會被打斷拾徙,程序會去處理之。
  3. 有多個響應處理函數(shù)時順序

    • 事件因為都是與窗口相關的感局,所以事件回調(diào)時都是從當前窗口開始尼啡,一級一級向上派發(fā),直到有一個窗口返回true询微,截斷了事件的處理為止崖瞭。
    • 信號可以在注冊時顯示地指明槽的位置,如果沒有指明撑毛,默認是隨機順序书聚。

信號和槽的機制

當某個事件發(fā)生之后,比如藻雌,按鈕檢測到自己被點擊了一下雌续,它就會發(fā)出一個信號(signal)。這種發(fā)出是沒有目的的胯杭,類似廣播驯杜。如果有對象對這個信號感興趣,它就會使用連接(connect)函數(shù)做个,將想要處理的信號和自己的一個函數(shù)(槽函數(shù)(slot))綁定并處理這個信號鸽心。

  • 槽函數(shù)類似于回調(diào)函數(shù)滚局。
  • 調(diào)用時機
    一般情況下,信號發(fā)出后會立即執(zhí)行顽频。
    特殊情況:當使用queued connections時藤肢,情況略有不同,在這種情況下糯景,emit關鍵字后面的代碼將立即繼續(xù)嘁圈,插槽將稍后執(zhí)行。

屬性

聲明

參數(shù)

連接與斷開

信號連接信號

信號與槽(信號)個數(shù)的關系

信號的觸發(fā)

參考

https://blog.csdn.net/maizousidemao/article/details/104199773
Qt信號槽-原理分析
信號與槽的連接方式

  • 事件是對象蟀淮〕蠛ⅲ可以被任何QObject的實例收到和處理。

如何傳遞事件

事件發(fā)生時灭贷,qt創(chuàng)建了一個代表它的對象,

事件類型

事件處理

一般的事件傳遞方式是調(diào)用virtual函數(shù)略贮∩跖保可以把自己想做的處理寫在當前函數(shù),然后把其他的都傳遞給base類處理逃延。

void MyCheckBox::mousePressEvent(QMouseEvent *event)
{
    if (event->button() == Qt::LeftButton) {
        // handle left mouse button here
    } else {
        // pass on other buttons to base class
        QCheckBox::mousePressEvent(event);
    }
}

更通用的處理方式:

bool MyWidget::event(QEvent *event)
{
    if (event->type() == QEvent::KeyPress) {
        QKeyEvent *ke = static_cast<QKeyEvent *>(event);
        if (ke->key() == Qt::Key_Tab) {
            // special tab handling here
            return true;
        }
    } else if (event->type() == MyCustomEventType) {
        MyCustomEvent *myEvent = static_cast<MyCustomEvent *>(event);
        // custom event handling here
        return true;
    }

    return QWidget::event(event);
}

  • 注意返回值是true代表著事件處理完畢览妖,不再傳遞給下一個處理函數(shù)。

事件過濾

可以在事件處理之前先通過filter揽祥,阻止特定的event傳遞給target widget讽膏,通過installEventFilter和removeEventFilter控制。

bool FilterObject::eventFilter(QObject *object, QEvent *event)
{
    if (object == target && event->type() == QEvent::KeyPress) {
        QKeyEvent *keyEvent = static_cast<QKeyEvent *>(event);
        if (keyEvent->key() == Qt::Key_Tab) {
            // Special tab handling
            return true;
        } else
            return false;
    }
    return false;
}

發(fā)送事件

用戶可以自定義自己的事件拄丰,并生成一個實例府树,通過sendEvent()和postEvent()發(fā)送它們。

多線程

兩種方式

1. 利用moveToThread()(推薦使用)

原型:void QObject::moveToThread(QThread *targetThread)

myObject->moveToThread(QApplication::instance()->thread());

改變該對象與線程之間執(zhí)行的關系料按,并不改變誰擁有該對象奄侠,只是讓該對象執(zhí)行成員函數(shù)時利用了target thread≡乜螅「在哪創(chuàng)建就屬于哪」這句話放在任何地方都是適用的垄潮。

  • 注意
    使用 moveToThread() 有一些需要注意的地方,首先就是類對象不能有父對象闷盔,否則無法將該對象“移動”到新線程弯洗。如果類對象保存在棧上,自然銷毀由操作系統(tǒng)自動完成逢勾;如果是保存在堆上牡整,沒有父對象的指針要想正常銷毀,需要將線程的 finished() 信號關聯(lián)到 QObject 的 deleteLater() 讓其在正確的時機被銷毀溺拱。其次是該對象一旦“移動”到新線程果正,那么該對象中的計時器(如果有 QTimer 等計時器成員變量)將重新啟動炎码。

2. 繼承QThread類,并重寫run()秋泳。

  • 全局線程(和UI一直存在的線程)
  • 局部線程(用完即釋放的線程)
    它們的結(jié)束方式不一樣潦闲。

注意如何正確退出一個線程

參考

https://blog.csdn.net/czyt1988/article/details/64441443

多線程

線程池

  • 使用QRunnable+QThreadPool
    QRunnable表示一個可執(zhí)行的任務,把它放到QThreadPool里的線程中執(zhí)行迫皱。

消息隊列

一歉闰、什么是Qt消息循環(huán)

Qt消息循環(huán),就是從一個隊列中不斷取出消息卓起,并響應消息的過程和敬。窗體的鼠標、鍵盤戏阅、輸入法昼弟、繪制,各種消息奕筐,都來自于Qt的消息循環(huán)舱痘。以Windows操作系統(tǒng)為例,Qt接管Windows原生窗口消息离赫,并翻譯成Qt的消息芭逝,派發(fā)給程序下的各個子對象、子QWidget等渊胸,通過接管層旬盯,可以很好屏蔽不同平臺之間的差異性,開發(fā)人員不需要關心Windows或者X11的消息的差異性翎猛,只需要搞清楚各個QEvent之間是什么含義胖翰。

最開始的Qt消息循環(huán)開始于QCoreApplication::exec()。用戶創(chuàng)建出一個QCoreApplication切厘,或者說更多情況下是QApplication泡态,執(zhí)行QCoreApplication::exec(),一個應用程序便開始了迂卢。QCoreApplication會不斷從操作系統(tǒng)獲取消息某弦,并且分發(fā)給QObject。

如果沒有消息循環(huán)而克,那么Qt的信號和槽無法完全使用靶壮,有些函數(shù)也無法正確執(zhí)行。舉個例子员萍,通過QueuedConnection連接的信號腾降,其實是將一個事件壓入了消息循環(huán),如果沒有QCoreApplication::exec()碎绎,那么這個消息循環(huán)將永遠無法派發(fā)到指定的對象螃壤。

二抗果、什么是線程相關性

準確點來說,應該是指QObject的線程相關性奸晴。以Qt文檔中的示意圖來作說明:

image

當我們創(chuàng)建一個QObject時冤馏,它會與創(chuàng)建自己所在的線程綁定。它參與的消息循環(huán)寄啼,其實是它所在線程的消息循環(huán)逮光,如上圖所示。假如某個線程沒有默認的QThread::exec()墩划,那么該線程上的QObject則無法接收到事件涕刚。另外,如果兩個不同線程的QObject需要相互通信乙帮,那么只能通過QueuedConnection的方式杜漠,異步通知對方線程,在下一輪消息循環(huán)處理QObject的消息察净。

QObject的線程相關性默認會和它的parent保持一致驾茴。如果一個QObject沒有parent,那么可以通過moveToThread塞绿,將它的線程相關性切換到指定線程。

了解QObject的線程相關性非常重要恤批,很多初學者常常分不清一個多線程中哪些QObject應該由主線程創(chuàng)建异吻,哪些應該由工作線程創(chuàng)建,我的觀點是喜庞,它參與哪個消息循環(huán)诀浪,就由哪個來創(chuàng)建。

正因為這樣的特性延都,我們才可以理解什么叫做AutoConnection雷猪。通過AutoConnect連接的兩個QObject,如果是在同一個線程晰房,那么可以直接調(diào)用(DirectConnection)求摇,如果不是在同一個線程,那么就通過事件通知的方式(QueuedConnection)來調(diào)用殊者。通過信號和槽与境、事件或者QueuedConnection方式來進行線程間的通訊,尤其是與UI線程通訊猖吴,永遠是最優(yōu)雅的方式之一摔刁。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市海蔽,隨后出現(xiàn)的幾起案子共屈,更是在濱河造成了極大的恐慌绑谣,老刑警劉巖,帶你破解...
    沈念sama閱讀 212,816評論 6 492
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件拗引,死亡現(xiàn)場離奇詭異借宵,居然都是意外死亡,警方通過查閱死者的電腦和手機寺擂,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,729評論 3 385
  • 文/潘曉璐 我一進店門暇务,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人怔软,你說我怎么就攤上這事垦细。” “怎么了挡逼?”我有些...
    開封第一講書人閱讀 158,300評論 0 348
  • 文/不壞的土叔 我叫張陵括改,是天一觀的道長。 經(jīng)常有香客問我家坎,道長嘱能,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 56,780評論 1 285
  • 正文 為了忘掉前任虱疏,我火速辦了婚禮惹骂,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘做瞪。我一直安慰自己对粪,他們只是感情好,可當我...
    茶點故事閱讀 65,890評論 6 385
  • 文/花漫 我一把揭開白布装蓬。 她就那樣靜靜地躺著著拭,像睡著了一般。 火紅的嫁衣襯著肌膚如雪牍帚。 梳的紋絲不亂的頭發(fā)上儡遮,一...
    開封第一講書人閱讀 50,084評論 1 291
  • 那天,我揣著相機與錄音暗赶,去河邊找鬼鄙币。 笑死,一個胖子當著我的面吹牛蹂随,可吹牛的內(nèi)容都是我干的爱榔。 我是一名探鬼主播,決...
    沈念sama閱讀 39,151評論 3 410
  • 文/蒼蘭香墨 我猛地睜開眼糙及,長吁一口氣:“原來是場噩夢啊……” “哼详幽!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 37,912評論 0 268
  • 序言:老撾萬榮一對情侶失蹤唇聘,失蹤者是張志新(化名)和其女友劉穎版姑,沒想到半個月后,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體迟郎,經(jīng)...
    沈念sama閱讀 44,355評論 1 303
  • 正文 獨居荒郊野嶺守林人離奇死亡剥险,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,666評論 2 327
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了宪肖。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片表制。...
    茶點故事閱讀 38,809評論 1 341
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖控乾,靈堂內(nèi)的尸體忽然破棺而出么介,到底是詐尸還是另有隱情,我是刑警寧澤蜕衡,帶...
    沈念sama閱讀 34,504評論 4 334
  • 正文 年R本政府宣布壤短,位于F島的核電站,受9級特大地震影響慨仿,放射性物質(zhì)發(fā)生泄漏久脯。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 40,150評論 3 317
  • 文/蒙蒙 一镰吆、第九天 我趴在偏房一處隱蔽的房頂上張望帘撰。 院中可真熱鬧,春花似錦万皿、人聲如沸摧找。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,882評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽慰于。三九已至钮科,卻和暖如春唤衫,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背绵脯。 一陣腳步聲響...
    開封第一講書人閱讀 32,121評論 1 267
  • 我被黑心中介騙來泰國打工佳励, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留赂乐,地道東北人逆屡。 一個月前我還...
    沈念sama閱讀 46,628評論 2 362
  • 正文 我出身青樓,卻偏偏與公主長得像赘被,于是被迫代替她去往敵國和親悴侵。 傳聞我的和親對象是個殘疾皇子瞧剖,可洞房花燭夜當晚...
    茶點故事閱讀 43,724評論 2 351