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 方法中处理你的数据 。
注意不能直接调用run方法,而是通过 start 方法间接调用它,否则界面仍有可能被“冻结”住 。
接下来是使用上面你定义的线程:
self.myThread = YourThreadName()self.myThread.start()如此,在run方法中写的代码得以执行,可以使用像isRunning这样的方法检测线程是否正在运行 。
你可能会经常用到这些QThread的方法: quit 、 start 、 terminate 、 isFinished 、 isRunning 。
还有QThread的这些信号: finished 、 started 、 terminated 。
2.我们的程序介绍完QThread类,下面回到我们的新闻获取程序 。
我们可以很容易地将获取新闻的代码移到QThread类,除了修改run方法,其它地方基本保持原样 。
另一个小的变化是,需要将新闻关键字的列表传到线程类中,从而在run方法中使用这些关键字 。
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 方法是从之前的新闻获取代码直接复制过来的,在run方法中遍历之前设置的关键字subreddits 。
主界面类:
self.testThread.setSubReddit(subreddit_list)self.testThread.start()OK,程序将在单独的线程中运行,然后根据关键字获取所有热点新闻 。
但是,界面中的元素还没有得到更新,没有反馈给用户,所以我们还需做些什么 。
当然,不能简单地在线程类中这么写:
self.searchProgBar.setValue(int) ,因为它指向QThread对象,而不是UI对象 。
在数据处理线程和UI线程之间沟通的正确方法是使用“信号” 。
四、信号数据获取线程在背后运行,主界面线程需要获得数据(比如新闻标题),从而更新界面元素(比如进度条和新闻列表)
下面先讲一下Pyqt的信号,它与C++中信号槽连接有所不同 。
1.内建信号获取数据结束之后需要通知用户,我们将使用一个所有QThread实例都有的信号 。
首先写一个线程结束后我们想要执行的代码,比如打印一条信息,我们在主界面类中这么写:
def threadFinished(self):print('获取结束')接下来是信号的连接,将QThread实例发出的信号与我们线程结束后打印信息的函数连接起来:
self.testThread = GetPostThread()内建信号与槽函数的连接很直接,自定义信号与之唯一的不同就是,我们首先需要在QThread类中定义一个信号,在主线程中的写法是一样的 。
self.testThread.finished.connect(self.threadFinished)
所以接下来——
2.自定义信号想要像内建信号一样使用自定义信号,首先需要定义它们,在QThread类中定义信号:
postSignal = pyqtSignal(str)注意:定义的信号有一个参数,类型是字符串str 。run方法中处理并获得数据,然后通过信号将其发出:
def run(self):for subreddit in self.subreddits:top_post = self._get_top_post(subreddit)self.postSignal.emit(top_post)self.sleep(2)主线程获得信号,并将它与信号处理函数(槽函数)相连接:self.testThread.postSignal.connect(self.getPostSlot)信号发出时带有一个字符串参数(在这里是新闻的标题),定义信号处理函数时也设置一个额外的参数,获得传来的字符串:def getPostSlot(self, top_post):self.resultList.addItem(top_post)self.searchProgBar.setValue(self.searchProgBar.value() + 1)将获得的新闻标题呈现在列表中,并调整进度条的数值 。五、总结到此为止,我们已经完成所有工作:
- 从新闻网站获取新闻的线程
- 线程与主线程的连接
- 如何实现自定义信号
- 如何使用内建信号

文章插图
你将看到:
