首页 > 编程语言 > 详细

Qt——线程(一)

时间:2017-02-09 17:23:54      阅读:223      评论:0      收藏:0      [点我收藏+]

本文主要介绍Qt中线程QThread的用法,参考(翻译+修改)了一篇特别好的文章:PyQt: Threading Basics Tutorial。本文虽然使用的是PyQt,但与C++中Qt的用法大同小异,不必在意语言的不同。

在这篇文章中,我将写一个抓取新闻的程序(使用新闻网站reddit.com的api),每隔2秒发出一个关键字,获得与该关键字相关的热度最高的新闻。

我们需要达到以下几个目标:

  • 用户在输入框中输入n个关键字,所有关键字以逗号,隔开
  • 使用一个列表来呈现获得的新闻标题
  • 用一个进度条来更新已获取到的新闻数目
  • 允许用户随时停止获取数据

最终界面如下(设计得很简单,因为界面不是本文的重点):

技术分享

 

一、代码片段

1.新闻获取部分

这部分不是教程的重点,只是从服务器获取并解析数据,所以不做过多讲解。

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):
    #从服务器获取数据
    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 ‘错误数据‘
    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‘, ‘linux‘, ‘learnpython‘]):
        print(post)#输出结果

网络请求是使用python的requests库。需要注意上面的 time.sleep(2) ,因为服务器只允许每隔2秒发一次请求,并返回正确的数据。

 

2.基本界面代码

界面部分,我们可以在代码中写各个控件和布局,也可以用Qt Designer设计好,然后生成相应的代码(可以参考该文:点我)。

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线程中完成,所以执行函数获取新闻时,你的程序将会被“冻结”住。

就像这样:

技术分享

  • 主线程被锁住
  • 直到程序执行结束,列表list才会更新
  • 输入框以及所有界面元素都无法使用
  • 一旦函数执行,就没法将其中止

下面是主要代码(点击开始按钮,进入槽函数,获取新闻数据):

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(‘没有搜索内容‘)
            return
        self.resultList.clear()
        for post in self.get_top_from_subreddits(subreddit_list):
            self.resultList.addItem(post)

  

三、使用多线程

我们已经看到没有使用多线程将会发生什么事,下面将使用QThread类重写我们的代码。

我们要做的就是写一个线程,这个线程与之前的 get_top_post 和 get_top_from_subreddits 做相同的工作,当获得新数据时就更新界面,而且允许用户点击“停止”按钮停止获取数据。

 

1.QThread的基本结构

在这里我们要使用的QThread类很简单,它的整体结构如下:

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

你可以通过它的构造方法__init__给线程传参数。不能直接调用run方法,而是通过start间接调用run,否则你的界面仍有可能被“冻结”住。

所以你可以像这样使用上面的自定义线程:

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

  

如此,在run方法中写的代码将被执行,你可以使用像isRunning这样的方法检测线程是否正在运行。

大多数时候你只需使用下面的方法: quit 、 start 、 terminate 、 isFinished 、 isRunning 。QThread的这些信号也很有用: finished 、 started 、 terminated 

Qt——线程(一)

原文:http://www.cnblogs.com/hellovenus/p/6382991.html

(0)
(0)
   
举报
评论 一句话评论(0
关于我们 - 联系我们 - 留言反馈 - 联系我们:wmxa8@hotmail.com
© 2014 bubuko.com 版权所有
打开技术之扣,分享程序人生!