【專題7:qt上位機詳解】 之 【2.信號與槽 - 使用(重點)】

一個默默耕耘的工程師…

各專題目錄
【專題1:工作兩年再學嵌入式】
【專題2:freertos系統詳解】
【專題3:從0到1寫嵌入式操作系統】
【專題4:直流無刷電機控制】
【專題5:從0到1寫bootloader、iap升級和產品量產】
【專題6:mcu硬件電路設計】
【專題7:qt上位機詳解】
【專題8:linux應用及qt移植】
【專題9:從linux內核借鑑寫代碼的思路】
【專題10:面向對象和事件驅動】
【專題11:從0到1開發儀表】
【專題12:常用複雜模塊從0到1】
【專題13:讀書筆記】

1.信號和槽函數的定義和添加

  Qt本身提供了很多控件,這個控件也定義了很多信號和槽函數。

  • 方式一:直接通過界面設計器來添加,這種方式最常用。
    在這裏插入圖片描述在這裏插入圖片描述
  • 方式二:直接通過信號與槽編輯器來添加。
    在這裏插入圖片描述在這裏插入圖片描述

2.什麼時候需要定義信號

  當我們需要對界面的內容做改變的時候就需要定義自己的信號。

  子線程想更新界面的內容,如果此時子線程直接調用控件的槽函數(每個控件都有對應的槽函數來修改界面,譬如Label控件,setText()函數就是Label控件用來修改控件文字的槽函數,如果將Label定義爲一個全局變量,在子線程中使用該全局變量修改Label的內容,軟件可能會宕掉,因爲QT的主線程就是用來處理信號槽的,該主線程也可能會調用到該Label控件的setText()槽函數,子線程和主線程同時調用,系統就會宕掉)更改控件的內容,系統會宕掉。

  場景:譬如用子線程上傳文件,同時需要更新UI進度條,如果此時子線程直接調用進度條線程的槽函數,軟件會宕掉。我們可以在主線程中自定義一個槽函數,在槽函數中調用進度條控件的槽函數,然後在子線程中自定義一個信號,最後只有在主線程的初始化函數中使用connect將子線程的信號與主線程的槽函數進行綁定,每當子線程需要更新UI時,只需要調用一次自定義信號即可。信號是子線程的,槽函數是主線程的,這樣兩者直接互不干擾,我們綁定好之後,QT會負責將兩者進行關聯。

3.Q_OBJECT說明

  如果你定義的類需要添加信號槽,就需要在頭文件的第一行添加這個宏。

  這個宏對於我們沒有任何意義,它主要是給MOC程序用的。我們調用connect綁定好信號與槽之後,當我們發送信號時,QT爲什麼就知道要調用哪個函數呢?信號會被髮送到隊列中,主線程的循環會讀取隊列,然後調用該消息對應的處理函數。一個信號可以綁定多個槽函數來接收自己,一個槽函數也可以綁定多個信號。這種複雜的關聯,僅僅靠一個connect函數的綁定還不夠,還需要MOC程序自動幫我們生成一部分代碼,MOC程序只會處理頭文件中帶Q_OBJECT宏的類。Q_OBJECT其實就是一個字符串,MOC會查詢所有頭文件,當匹配到Q_OBJECT字符串時,就會幫我們生成信號槽的部分代碼。

  如果自己的類需要使用信號槽,但又沒有加這個宏,會導致槽收不到信號等問題。QT本身也有一些BUG,如果明明加了這個宏,但在編譯信息中仍然沒有看到MOC程序被調用,生成對應的文件。原因:Q_OBJECT前後可能存在某些其他字符,將Q_OBJECT刪除,重新輸入一遍即可。
總結:
  QT會查詢頭文件中是否包含Q_OBJECT字符串,如果包含,會進一步查詢關鍵字signals,函數定義前面有singnals的,就說明是一個信號,MOC會實現信號函數的定義(注意,我們定義的信號函數只有聲明,沒有定義,其定義/函數的具體的實現代碼由MOC自動完成),同時也會查詢函數聲明的前面是否包含public slots,QT會生成“槽函數和信號的關聯”這部分代碼。

  當我們使用界面編輯器給一個button的點擊信號綁定widget的close槽函數時,觀察編譯信息:
(1)系統自動在頭文件中添加了Q_OBJECT宏。
在這裏插入圖片描述
(2)編譯信息。
在這裏插入圖片描述
  moc_widget.cpp就是moc程序自動生成的,該文件在debug或release目錄下,可以打開研究一下。
(3)將頭文件中的Q_OBJECT刪除,再觀察編譯信息(編譯報錯)。
在這裏插入圖片描述
如果信號與槽沒有起作用,可以觀察編譯過程,看看moc程序的執行過程是否正確。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章