QThread多線程
????????QThread是Qt線程類中最核心的底層類。由于PyQt 的跨平臺(tái)特性,QThread要隱藏所有與平臺(tái)相關(guān)的代碼。要使用QThread開始一個(gè)線程,可以創(chuàng)建它的一個(gè)子類,然后覆蓋其QThread.run()函數(shù)。
接下來創(chuàng)建一個(gè)新的線程。
????????可以看出,PyQt的線程的使用非常簡單一建立一個(gè)自定 義的類(如Thread),
使它繼承自QThread,并實(shí)現(xiàn)其run(方法即可。
????????在使用線程時(shí)可以直接得到Thread實(shí)例,調(diào)用其start()函數(shù)即可啟動(dòng)線程。線
程啟動(dòng)之后,會(huì)自動(dòng)調(diào)用其實(shí)現(xiàn)的run方法,該方法就是線程的執(zhí)行函數(shù)。
????????業(yè)務(wù)的線程任務(wù)就寫在run()函數(shù)中,當(dāng)run()退 出之后線程基本就結(jié)束了。QThread有started 和finished 信號(hào),可以為這兩個(gè)信號(hào)指定槽函數(shù),在線程啟動(dòng)和結(jié)束時(shí)執(zhí)行一段代碼進(jìn)行資源的初始化和釋放操作。更靈活的使用方法是,在自定義的QThread實(shí)例中自定義信號(hào),并將信號(hào)連接到指定的槽函數(shù),當(dāng)滿足一定的業(yè)務(wù)條件后發(fā)射此信號(hào)。
1、QThread類中的常用方法和信號(hào)
QThread類中的常用方法如下表所示。

QThread類中的常用信號(hào)如下表所示:

2、QThread實(shí)例
當(dāng)在窗口中顯示的數(shù)據(jù)比較簡單時(shí),可以把讀取數(shù)據(jù)的業(yè)務(wù)邏輯放在窗口的初始化代碼中;但如果讀取數(shù)據(jù)的時(shí)間較長,比如網(wǎng)絡(luò)請(qǐng)求數(shù)據(jù)的時(shí)間比較長,則可以把這部分邏輯放在QHread線程中,實(shí)現(xiàn)界面的數(shù)據(jù)顯示和數(shù)據(jù)讀取的分離,滿足MVC(模型--視圖--控制器)設(shè)計(jì)模式的要求。
實(shí)例演示1:
運(yùn)行程序,點(diǎn)擊開始,顯示效果如下:

代碼分析:
????????在這個(gè)例子中,單擊開始按鈕,會(huì)在后臺(tái)定時(shí)讀取數(shù)據(jù),并把返回的數(shù)據(jù)顯示在界面中,首先使用以下代碼進(jìn)行布局,把列表控件和按鈕控件放在柵格布局管理器中:
????????然后將按鈕的clicked信號(hào)連接到slotStart()槽函數(shù),當(dāng)單擊“開始”按鈕時(shí)發(fā)射此信號(hào):
????????比較負(fù)載的是線程的信號(hào),將線程的sinOut信號(hào)連接到slotAdd()槽函數(shù)。slotAdd()函數(shù)負(fù)責(zé)在列表控件中動(dòng)態(tài)添加字符串條目。
????????定義一個(gè)線程類,繼承自QThread類,當(dāng)線程啟動(dòng)后,執(zhí)行run()函數(shù)。
????????在上一個(gè)例子中,雖然解決了界面的數(shù)據(jù)顯示和數(shù)據(jù)讀取的分離,但是如果數(shù)據(jù)讀取非常耗費(fèi)時(shí)間,則會(huì)造成界面卡死。接下來,我們看下一個(gè)耗費(fèi)很長時(shí)間讀取數(shù)據(jù)的例子:
實(shí)例演示2:
運(yùn)行程序,顯示效果如下圖:

????????在這個(gè)例子中,在主界面中有一個(gè)用于顯示時(shí)間的LCD數(shù)字面板,還有一個(gè)用于啟動(dòng)任務(wù)的按鈕。用戶單擊“測(cè)試”按鈕后,將開始- -次非常耗時(shí)的計(jì)算(在程序中用一個(gè)2 000 000 000次的循環(huán)來模擬這次非常耗時(shí)的工作,在真實(shí)的程序中可能是一個(gè)網(wǎng)絡(luò)下載操作,從網(wǎng)絡(luò)上下載一個(gè)很大的視頻文件),同時(shí)LCD數(shù)字面板開始顯示所用的毫秒數(shù),并通過一一個(gè)計(jì)時(shí)器進(jìn)行更新。計(jì)算完成后,計(jì)時(shí)器停止。這是一個(gè)很簡單的應(yīng)用,也看不出有任何問題。但是當(dāng)開始運(yùn)行程序時(shí),問題就來了:單擊“測(cè)試”按鈕之后,程序界面直接停止響應(yīng),直到循環(huán)結(jié)束才開始重新更新,于是計(jì)時(shí)器始終顯示0。
????在PyQt中所有的窗口都在UI主線程中(就是執(zhí)行了QApplication.exec(的線程),在這個(gè)線程中執(zhí)行耗時(shí)的操作會(huì)阻塞UI 線程,從而讓窗口停止響應(yīng)。如果窗口長時(shí)間沒有響應(yīng),則會(huì)影響用戶體驗(yàn),更嚴(yán)重的會(huì)導(dǎo)致程序崩潰。所以,為了避免出現(xiàn)這樣的問題,要使用QThread開啟一個(gè)新的線程,在這個(gè)線程中完成耗時(shí)的操作。
實(shí)例演示3:分離主線程與工作線程
運(yùn)行結(jié)果如下:
