日日操夜夜添-日日操影院-日日草夜夜操-日日干干-精品一区二区三区波多野结衣-精品一区二区三区高清免费不卡

公告:魔扣目錄網(wǎng)為廣大站長提供免費收錄網(wǎng)站服務(wù),提交前請做好本站友鏈:【 網(wǎng)站目錄:http://www.ylptlb.cn 】, 免友鏈快審服務(wù)(50元/站),

點擊這里在線咨詢客服
新站提交
  • 網(wǎng)站:51998
  • 待審:31
  • 小程序:12
  • 文章:1030137
  • 會員:747

本文主要介紹Qt中線程類QThread的用法

在這篇文章中,將寫一個獲取熱點新聞的程序,每隔2秒發(fā)送一個關(guān)鍵字,從服務(wù)器獲得與該關(guān)鍵字相關(guān)的一條熱點新聞。

我們的目標是實現(xiàn)以下幾個功能:

  • 用戶在輸入框中輸入n個關(guān)鍵字,以英文的逗號,隔開
  • 用一個搜索結(jié)果列表來呈現(xiàn)所獲得的新聞標題
  • 使用進度條更新已獲得的新聞數(shù)目
  • 用戶隨時可以停止獲取數(shù)據(jù)

界面設(shè)計如下圖:

 

上面是一個關(guān)鍵字輸入框QLineEdit,中間使用QListWidget呈現(xiàn)獲得的數(shù)據(jù),下面是QProgressBar更新進度,最下面有一個停止按鈕和一個開始按鈕。

一、代碼片段

1.新聞獲取部分

我們使用接口,從服務(wù)器獲取數(shù)據(jù)。

import json
import time
import requests
 
agent = 'Mozilla/5.0 (windows NT 6.2; WOW64) AppleWebKit/537.36 (Khtml, like Gecko) Chrome/57.0.2987.8 Safari/537.36'
headers = {
    'User-Agent': agent
}
 
def get_top_post(subreddit):
    #從服務(wù)器獲取數(shù)據(jù)
    url = "https://www.reddit.com/r/{}.json?limit=1".format(subreddit)
    try:
        restext = requests.get(url, headers=headers)
        data = json.loads(restext.text)
        top_post = data['data']['children'][0]['data']
    except Exception as e:
        print(e)
        return '錯誤數(shù)據(jù)'
    return "'{title}' by {author} in {subreddit}".format(**top_post)
 
def get_top_from_subreddits(subreddits):
    for subreddit in subreddits:
        yield get_top_post(subreddit)
        time.sleep(2)
 
if __name__ == '__main__':
    for post in get_top_from_subreddits(['Python/ target=_blank class=infotextkey>Python', 'php', 'learnpython']):
        print(post)#輸出結(jié)果

上面是獲取并處理新聞數(shù)據(jù)的程序。需要注意的是其中 time.sleep(2) ,之所以每次發(fā)送請求要隔兩秒,是因為服務(wù)器出于性能考慮,只允許每2秒發(fā)送一次請求,否則可能會得到錯誤的數(shù)據(jù)。在這里有3個關(guān)鍵字,python、php、learnpython,所以整個過程持續(xù)了大約6秒。

不必在意其中實現(xiàn)的細節(jié),因為本文的重點是線程,而不是獲取數(shù)據(jù)。

【領(lǐng)更多QT學習資料,點擊下方鏈接免費領(lǐng)取↓↓,先碼住不迷路~】

點擊領(lǐng)取→Qt學習資料~

2.基本界面

我們可以在代碼中實現(xiàn)所有控件和布局;也可以用Qt Designer設(shè)計好,然后使用命令 pyuic5 -o yourui.py yourui.ui 生成界面代碼。

在這里,我用的是第一個方法:

def initUI(self):
  self.setWindowTitle('QThread Study')
 
    keywordLbl = QLabel('關(guān)鍵字(以逗號,隔開):')
    self.keywordEdit = QLineEdit()
    hrLayout = QHBoxLayout()
    hrLayout.addWidget(keywordLbl)
    hrLayout.addWidget(self.keywordEdit)
 
    resultLbl = QLabel('搜索結(jié)果:')
    self.resultList = QListWidget()
    vrLayout = QVBoxLayout()
    vrLayout.addWidget(resultLbl)
    vrLayout.addWidget(self.resultList)
 
    self.searchProgBar = QProgressBar()
    self.searchProgBar.setValue(0)
    self.stopBtn = QPushButton('停止')
    self.stopBtn.setEnabled(False)
    self.startBtn = QPushButton('開始')
    hrLayout1 = QHBoxLayout()
    hrLayout1.addWidget(self.stopBtn)
    hrLayout1.addWidget(self.startBtn)
 
    vrLayout1 = QVBoxLayout(self)
    vrLayout1.addLayout(hrLayout)
    vrLayout1.addLayout(vrLayout)
    vrLayout1.addWidget(self.searchProgBar)
    vrLayout1.addLayout(hrLayout1)

二、未使用多線程

如果沒有使用多線程,你可能會這么做:寫好新聞獲取的代碼、寫好界面代碼,接下來簡單地調(diào)用函數(shù)處理數(shù)據(jù)。這么做可以,但所有工作都在單獨的GUI線程中完成,所以執(zhí)行函數(shù)獲取新聞時,你的程序?qū)?ldquo;凍結(jié)”住。

就像這樣:

 

  • 主線程被鎖住
  • 直到程序執(zhí)行結(jié)束,搜索結(jié)果列表才會更新
  • 輸入框以及其它界面中的元素都無法使用
  • 一旦函數(shù)開始執(zhí)行,就沒法停止獲取數(shù)據(jù)

下面是主要代碼(點擊開始按鈕 - 進入槽函數(shù) - 獲取新聞數(shù)據(jù)):

class ThreadTestUI(QWidget):
    def __init__(self, parent = None):
        super().__init__(parent)
        self.initUI()
        #建立信號槽連接
        self.startBtn.clicked.connect(self.startBtnClicked)
 
    def startBtnClicked(self):
        subreddit_list = str(self.keywordEdit.text()).split(',')
        if subreddit_list == ['']:
            print('沒有搜索內(nèi)容')
            return
        self.resultList.clear()
        for post in self.get_top_from_subreddits(subreddit_list):
            self.resultList.addItem(post)

三、使用多線程

沒有使用多線程將導(dǎo)致程序卡住,體驗很差,下面將使用QThread類重寫我們的代碼。

首先要做的就是寫一個線程,這個線程與之前新聞獲取部分 get_top_post 和 get_top_from_subreddits 做相同的事,每當獲得新數(shù)據(jù)就立即更新界面,而且允許用戶點擊“停止”按鈕停止獲取數(shù)據(jù)。

1.QThread的基本結(jié)構(gòu)

QThread類很簡單,它的整體結(jié)構(gòu)如下:

from PyQt4.QtCore import QThread
 
class YourThreadName(QThread):
 
    def __init__(self):
        QThread.__init__(self)
 
    def __del__(self):
        self.wait()
 
    def run(self):
        # your logic here

你可以通過給構(gòu)造方法 __init__ 添加參數(shù),將數(shù)據(jù)傳給線程。

在 run 方法中處理你的數(shù)據(jù)。

注意不能直接調(diào)用run方法,而是通過 start 方法間接調(diào)用它,否則界面仍有可能被“凍結(jié)”住。

接下來是使用上面你定義的線程:


self.myThread = YourThreadName()
self.myThread.start()

如此,在run方法中寫的代碼得以執(zhí)行,可以使用像isRunning這樣的方法檢測線程是否正在運行。

你可能會經(jīng)常用到這些QThread的方法: quit 、 start 、 terminate 、 isFinished 、 isRunning 。

還有QThread的這些信號: finished 、 started 、 terminated 。

2.我們的程序

介紹完QThread類,下面回到我們的新聞獲取程序。

我們可以很容易地將獲取新聞的代碼移到QThread類,除了修改run方法,其它地方基本保持原樣。

另一個小的變化是,需要將新聞關(guān)鍵字的列表傳到線程類中,從而在run方法中使用這些關(guān)鍵字。

def setSubReddit(self, subReddit):
    self.subreddits = subReddit
 
def run(self):
    for subreddit in self.subreddits:
        top_post = self._get_top_post(subreddit)
        self.sleep(2)

_get_top_post 方法是從之前的新聞獲取代碼直接復(fù)制過來的,在run方法中遍歷之前設(shè)置的關(guān)鍵字subreddits。

主界面類:

self.testThread.setSubReddit(subreddit_list)
self.testThread.start()

OK,程序?qū)⒃趩为毜木€程中運行,然后根據(jù)關(guān)鍵字獲取所有熱點新聞。

但是,界面中的元素還沒有得到更新,沒有反饋給用戶,所以我們還需做些什么。

當然,不能簡單地在線程類中這么寫:
self.searchProgBar.setValue(int) ,因為它指向QThread對象,而不是UI對象。

在數(shù)據(jù)處理線程和UI線程之間溝通的正確方法是使用“信號”。

四、信號

數(shù)據(jù)獲取線程在背后運行,主界面線程需要獲得數(shù)據(jù)(比如新聞標題),從而更新界面元素(比如進度條和新聞列表)

下面先講一下Pyqt的信號,它與C++中信號槽連接有所不同。

1.內(nèi)建信號

獲取數(shù)據(jù)結(jié)束之后需要通知用戶,我們將使用一個所有QThread實例都有的信號。

首先寫一個線程結(jié)束后我們想要執(zhí)行的代碼,比如打印一條信息,我們在主界面類中這么寫:

def threadFinished(self):
    print('獲取結(jié)束')

接下來是信號的連接,將QThread實例發(fā)出的信號與我們線程結(jié)束后打印信息的函數(shù)連接起來:

self.testThread = GetPostThread()

self.testThread.finished.connect(self.threadFinished)

內(nèi)建信號與槽函數(shù)的連接很直接,自定義信號與之唯一的不同就是,我們首先需要在QThread類中定義一個信號,在主線程中的寫法是一樣的。

所以接下來——

2.自定義信號

想要像內(nèi)建信號一樣使用自定義信號,首先需要定義它們,在QThread類中定義信號:

postSignal = pyqtSignal(str)

注意:定義的信號有一個參數(shù),類型是字符串str。

run方法中處理并獲得數(shù)據(jù),然后通過信號將其發(fā)出:

def run(self):
    for subreddit in self.subreddits:
        top_post = self._get_top_post(subreddit)
        self.postSignal.emit(top_post)
        self.sleep(2)

主線程獲得信號,并將它與信號處理函數(shù)(槽函數(shù))相連接:

self.testThread.postSignal.connect(self.getPostSlot)

信號發(fā)出時帶有一個字符串參數(shù)(在這里是新聞的標題),定義信號處理函數(shù)時也設(shè)置一個額外的參數(shù),獲得傳來的字符串:

def getPostSlot(self, top_post):
self.resultList.addItem(top_post)
self.searchProgBar.setValue(self.searchProgBar.value() + 1)

將獲得的新聞標題呈現(xiàn)在列表中,并調(diào)整進度條的數(shù)值。

五、總結(jié)

到此為止,我們已經(jīng)完成所有工作:

  • 從新聞網(wǎng)站獲取新聞的線程
  • 線程與主線程的連接
  • 如何實現(xiàn)自定義信號
  • 如何使用內(nèi)建信號

注意:在QThread線程類中處理數(shù)據(jù),通過信號將數(shù)據(jù)發(fā)送到主界面線程,進而更新界面元素

看一下現(xiàn)在界面是怎么樣的吧:

 

你將看到:

  • 每獲得一條新數(shù)據(jù),界面立即更新
  • 界面仍然可響應(yīng),比如拖動、改變輸入框內(nèi)容
  • 主線程沒有被鎖住
  • 隨時可以點擊停止按鈕,停止獲取數(shù)據(jù)

分享到:
標簽:開發(fā) Qt
用戶無頭像

網(wǎng)友整理

注冊時間:

網(wǎng)站:5 個   小程序:0 個  文章:12 篇

  • 51998

    網(wǎng)站

  • 12

    小程序

  • 1030137

    文章

  • 747

    會員

趕快注冊賬號,推廣您的網(wǎng)站吧!
最新入駐小程序

數(shù)獨大挑戰(zhàn)2018-06-03

數(shù)獨一種數(shù)學游戲,玩家需要根據(jù)9

答題星2018-06-03

您可以通過答題星輕松地創(chuàng)建試卷

全階人生考試2018-06-03

各種考試題,題庫,初中,高中,大學四六

運動步數(shù)有氧達人2018-06-03

記錄運動步數(shù),積累氧氣值。還可偷

每日養(yǎng)生app2018-06-03

每日養(yǎng)生,天天健康

體育訓(xùn)練成績評定2018-06-03

通用課目體育訓(xùn)練成績評定