Qt开发——线程类QThread

本文主要介绍Qt中线程类QThread的用法在这篇文章中,将写一个获取热点新闻的程序,每隔2秒发送一个关键字,从服务器获得与该关键字相关的一条热点新闻 。
我们的目标是实现以下几个功能:

  • 用户在输入框中输入n个关键字,以英文的逗号,隔开
  • 用一个搜索结果列表来呈现所获得的新闻标题
  • 使用进度条更新已获得的新闻数目
  • 用户随时可以停止获取数据
界面设计如下图:
Qt开发——线程类QThread

文章插图
 
上面是一个关键字输入框QLineEdit,中间使用QListWidget呈现获得的数据,下面是QProgressBar更新进度,最下面有一个停止按钮和一个开始按钮 。
一、代码片段1.新闻获取部分我们使用接口,从服务器获取数据 。
import jsonimport timeimport 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):#从服务器获取数据url = "https://www.reddit.com/r/{}.json?limit=1".format(subreddit)try:restext = requests.get(url, headers=headers)data = https://www.isolves.com/it/cxkf/bk/2022-11-01/json.loads(restext.text)top_post = data['data']['children'][0]['data']except Exception as e:print(e)return '错误数据'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)#输出结果上面是获取并处理新闻数据的程序 。需要注意的是其中 time.sleep(2),之所以每次发送请求要隔两秒,是因为服务器出于性能考虑,只允许每2秒发送一次请求,否则可能会得到错误的数据 。在这里有3个关键字,python、php、learnpython,所以整个过程持续了大约6秒 。
不必在意其中实现的细节,因为本文的重点是线程,而不是获取数据 。
【领更多QT学习资料,点击下方链接免费领取↓↓,先码住不迷路~】
点击领取→Qt学习资料~
2.基本界面我们可以在代码中实现所有控件和布局;也可以用Qt Designer设计好,然后使用命令 pyuic5 -o yourui.py yourui.ui 生成界面代码 。
在这里,我用的是第一个方法:
def initUI(self):self.setWindowTitle('QThread Study')keywordLbl = QLabel('关键字(以逗号,隔开):')self.keywordEdit = QLineEdit()hrLayout = QHBoxLayout()hrLayout.addWidget(keywordLbl)hrLayout.addWidget(self.keywordEdit)resultLbl = QLabel('搜索结果:')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)二、未使用多线程如果没有使用多线程,你可能会这么做:写好新闻获取的代码、写好界面代码,接下来简单地调用函数处理数据 。这么做可以,但所有工作都在单独的GUI线程中完成,所以执行函数获取新闻时,你的程序将会被“冻结”住 。
就像这样:
Qt开发——线程类QThread

文章插图
 
  • 主线程被锁住
  • 直到程序执行结束,搜索结果列表才会更新
  • 输入框以及其它界面中的元素都无法使用
  • 一旦函数开始执行,就没法停止获取数据
下面是主要代码(点击开始按钮 - 进入槽函数 - 获取新闻数据):
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('没有搜索内容')returnself.resultList.clear()for post in self.get_top_from_subreddits(subreddit_list):self.resultList.addItem(post)三、使用多线程没有使用多线程将导致程序卡住,体验很差,下面将使用QThread类重写我们的代码 。
首先要做的就是写一个线程,这个线程与之前新闻获取部分 get_top_post 和 get_top_from_subreddits 做相同的事,每当获得新数据就立即更新界面,而且允许用户点击“停止”按钮停止获取数据 。


推荐阅读