pyqt QThread 多线程实例(详细解释)

3 篇文章 0 订阅
3 篇文章 0 订阅

python 2.7  / Pyside (如果使用pyQt4,将Pyside直接替换PyQt4即可)

首先我们在Qt Designer中画好界面并自动生成design.py,注意生成后还要部分收到修改,然后创建main.py

design.py 主要负责写软件界面的文件。

main.py 主要负责写业务逻辑的文件。

design.py

# -*- coding: utf-8 -*-

from PySide import QtCore, QtGui

try:
    _fromUtf8 = QtCore.QString.fromUtf8
except AttributeError:
    def _fromUtf8(s):
        return s

try:
    _encoding = QtGui.QApplication.UnicodeUTF8
    def _translate(context, text, disambig):
        return QtGui.QApplication.translate(context, text, disambig, _encoding)
except AttributeError:
    def _translate(context, text, disambig):
        return QtGui.QApplication.translate(context, text, disambig)

class Ui_MainWindow(object):
    def setupUi(self, MainWindow):
        MainWindow.setObjectName(_fromUtf8("MainWindow"))
        MainWindow.resize(526, 373)
        self.centralwidget = QtGui.QWidget(MainWindow)
        self.centralwidget.setObjectName(_fromUtf8("centralwidget"))
        self.verticalLayout = QtGui.QVBoxLayout(self.centralwidget)
        self.verticalLayout.setObjectName(_fromUtf8("verticalLayout"))
        self.subreddits_input_layout = QtGui.QHBoxLayout()
        self.subreddits_input_layout.setObjectName(_fromUtf8("subreddits_input_layout"))
        self.label_subreddits = QtGui.QLabel(self.centralwidget)
        self.label_subreddits.setObjectName(_fromUtf8("label_subreddits"))
        self.subreddits_input_layout.addWidget(self.label_subreddits)
        self.edit_subreddits = QtGui.QLineEdit(self.centralwidget)
        self.edit_subreddits.setObjectName(_fromUtf8("edit_subreddits"))
        self.subreddits_input_layout.addWidget(self.edit_subreddits)
        self.verticalLayout.addLayout(self.subreddits_input_layout)
        self.label_submissions_list = QtGui.QLabel(self.centralwidget)
        self.label_submissions_list.setObjectName(_fromUtf8("label_submissions_list"))
        self.verticalLayout.addWidget(self.label_submissions_list)
        self.list_submissions = QtGui.QListWidget(self.centralwidget)
        self.list_submissions.setBatchSize(1)
        self.list_submissions.setObjectName(_fromUtf8("list_submissions"))
        self.verticalLayout.addWidget(self.list_submissions)
        self.progress_bar = QtGui.QProgressBar(self.centralwidget)
        self.progress_bar.setProperty("value", 0)
        self.progress_bar.setObjectName(_fromUtf8("progress_bar"))
        self.verticalLayout.addWidget(self.progress_bar)
        self.buttons_layout = QtGui.QHBoxLayout()
        self.buttons_layout.setObjectName(_fromUtf8("buttons_layout"))
        self.btn_stop = QtGui.QPushButton(self.centralwidget)
        self.btn_stop.setEnabled(False)
        self.btn_stop.setObjectName(_fromUtf8("btn_stop"))
        self.buttons_layout.addWidget(self.btn_stop)
        self.btn_start = QtGui.QPushButton(self.centralwidget)
        self.btn_start.setObjectName(_fromUtf8("btn_start"))
        self.buttons_layout.addWidget(self.btn_start)
        self.verticalLayout.addLayout(self.buttons_layout)
        MainWindow.setCentralWidget(self.centralwidget)

        self.retranslateUi(MainWindow)
        QtCore.QMetaObject.connectSlotsByName(MainWindow)

    def retranslateUi(self, MainWindow):
        MainWindow.setWindowTitle(_translate("MainWindow", "Threading Tutorial - nikolak.com", None))
        self.label_subreddits.setText(_translate("MainWindow", "Subreddits:", None))
        self.edit_subreddits.setPlaceholderText(_translate("MainWindow", "python,programming,linux,etc (comma separated)", None))
        self.label_submissions_list.setText(_translate("MainWindow", "Submissions:", None))
        self.btn_stop.setText(_translate("MainWindow", "Stop", None))
        self.btn_start.setText(_translate("MainWindow", "Start", None))

 

main.py

# -*- coding: utf-8 -*-
from PySide import QtGui
from PySide.QtCore import QThread, SIGNAL
import sys
import design
import urllib2
import json
import time


class getPostsThread(QThread):
    '''线程类'''
    def __init__(self, subreddits):
        QThread.__init__(self)
        self.subreddits = subreddits

    def __del__(self):
        self.wait()

    def _get_top_post(self, subreddit):
        """从唯一必需参数传递的subreddit返回带有顶部帖子标题,作者和subreddit名称的预格式化字符串。"""
        url = "https://www.reddit.com/r/{}.json?limit=1".format(subreddit)
        headers = {'User-Agent': 'nikolak@outlook.com tutorial code'}
        request = urllib2.Request(url, headers=headers)
        response = urllib2.urlopen(request)
        data = json.load(response)
        top_post = data['data']['children'][0]['data']
        return "'{title}' by {author} in {subreddit}".format(**top_post)

    def run(self):
        """用start()运行"""
        # 遍历self.subreddits列表中的每个项目(在__init__期间提供),并且对于每个项目,
        for subreddit in self.subreddits:
            # 获取有效subreddit名称的字符串,并使用reddit中的_get_top_post方法获取顶部帖子。将结果存储在名为top_post的局部变量中。
            top_post = self._get_top_post(subreddit)
            # 然后发出'SIGNAL add_post(QString)'信号,其中QString等于_get_top_post函数设置的top_post变量。
            self.emit(SIGNAL('add_post(QString)'), top_post)
            self.sleep(2)

class ThreadingTutorial(QtGui.QMainWindow, design.Ui_MainWindow):
    """主逻辑类,需要继承UI类"""
    def __init__(self):
        super(self.__class__, self).__init__()
        self.setupUi(self)
        # 将“启动”按钮链接到start_getting_top_posts函数中
        self.btn_start.clicked.connect(self.start_getting_top_posts)

    def start_getting_top_posts(self):
        # 获取信息
        # 获取s用户输入到QLineEdit字段中
        subreddit_list = str(self.edit_subreddits.text()).split(',')
        # 如果没有输入文字,这将等于''
        if subreddit_list == ['']:
            # 是否有任何东西可以从中获取,如果没有显示消息并中止
            QtGui.QMessageBox.critical(self, "No subreddits","You didn't enter any subreddits.",QtGui.QMessageBox.Ok)
            return


        # 初始化值
        # 设置进度条的最大值,可以是任意int,它将自动转换为x/100%值
        # 例如max_value = 3,current_value = 1,进度条将显示33%
        self.progress_bar.setMaximum(len(subreddit_list))
        # 将每次运行的值初始化设置为0
        self.progress_bar.setValue(0)


        # 创建线程
        # 我们创建一个新的getPostsThread线程实例,将subreddits列表传递给线程
        self.get_thread = getPostsThread(subreddit_list)


        # 连接
        # 接下来,我们将来自getPostsThread线程的事件连接到我们希望在这些信号被触发时运行的函数,这里介绍两种信号处理

        # 连接自定义信号
        # 添加返回信息将在本类的add_post方法中进行处理,并且线程将发出的信号是‘SIGNAL(“add_post(QString)”)’,
        # 其余我们可以用相同的方法来连接任何信号
        self.get_thread.connect(SIGNAL("add_post(QString)"), self.add_post)

        # 连接内置信号
        # 无论线程是完成还是终止,我们希望向用户显示已完成的通知,无论是主动终止还是已完成
        # 完成的信号将熄灭。所以我们不需要专门捕捉已终止,但如果我们想要的话,也可以去做。
        self.get_thread.connect(SIGNAL("finished()"), self.done)


        # 启动线程的事件
        self.get_thread.start()
        # 当线程开始运行时,能允许用户停止/终止线程,所以我们启用“停止”按钮
        self.btn_stop.setEnabled(True)
        # 我们将“停止”按钮的单击连接到QThread实例所具有的内置终止方法terminate/quit
        #self.btn_stop.clicked.connect(self.get_thread.terminate)
        self.btn_stop.clicked.connect(self.get_thread.quit)
        # 我们不希望用户在此线程运行时启动另一个线程,因此我们禁用了“启动”按钮。
        self.btn_start.setEnabled(False)

    def add_post(self, post_text):
        """将给定此函数的文本添加到我们GUI中的list_submissions QListWidget中,并将进度条的当前值增加1"""
        self.list_submissions.addItem(post_text)
        self.progress_bar.setValue(self.progress_bar.value() + 1)

    def done(self):
        # 禁用“停止”按钮,
        self.btn_stop.setEnabled(False)
        # 启用“启动”按钮
        self.btn_start.setEnabled(True)
        # 将进度条重置为0
        self.progress_bar.setValue(0)
        # 弹出提示信息
        QtGui.QMessageBox.information(self, "Done!", "Done fetching posts!")


def main():
    # 创建应用
    app = QtGui.QApplication(sys.argv)
    # 创建实例表单
    form = ThreadingTutorial()
    # 显示实例
    form.show()
    # 退出程序
    app.exec_()


if __name__ == '__main__':
    main()

 

https://nikolak.com/pyqt-threading-tutorial/

  • 2
    点赞
  • 17
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
使用QThreadPyQt5中开发多线程应用程序是很常见的,但有时候我们需要停止或者终止某个线程,这个时候要怎样做呢? PyQt5提供了一种简单有效的方式来终止线程,我们可以通过附加一个标志位来实现正常停止线程的操作。具体的过程如下: 1. 在需要终止的线程中定义一个布尔型变量,例如self._isRunning = True。 2. 在线程的run()方法中循环执行任务,并在合适的地方检查self._isRunning的状态。如果该变量为False,则结束循环并停止线程。 3. 在主线程中通过改变self._isRunning的值来控制线程的停止。 下面是一个简单的实例,演示如何通过设置布尔型变量来控制线程的停止: ```python import sys from PyQt5.QtCore import QThread, pyqtSignal from PyQt5.QtWidgets import QApplication, QWidget, QPushButton, QVBoxLayout class TestThread(QThread): stop_signal = pyqtSignal() def __init__(self, parent=None): super(TestThread, self).__init__(parent) self._isRunning = True def run(self): while self._isRunning: print('Thread is running...') self.sleep(1) self.stop_signal.emit() def stop(self): self._isRunning = False class MainWindow(QWidget): def __init__(self): super(MainWindow, self).__init__() self.initUI() def initUI(self): self.btn_start = QPushButton('Start', self) self.btn_stop = QPushButton('Stop', self) layout = QVBoxLayout(self) layout.addWidget(self.btn_start) layout.addWidget(self.btn_stop) self.btn_start.clicked.connect(self.startThread) self.btn_stop.clicked.connect(self.stopThread) self.thread = TestThread() self.thread.stop_signal.connect(self.stopCompleted) def startThread(self): self.thread.start() def stopThread(self): self.thread.stop() def stopCompleted(self): print('Thread stopped successfully!') if __name__ == '__main__': app = QApplication(sys.argv) mainWindow = MainWindow() mainWindow.show() sys.exit(app.exec_()) ``` 上述代码中,我们新定义了一个停止信号stop_signal,并在stop()方法中发射该信号。同时,在主窗口中也连接了stop_signal信号,以实现停止线程后的回调操作。 总的来说,在PyQt5中终止线程很简单,只需要在线程类中设置布尔型的变量,通过在主线程中改变该变量的值即可控制线程的停止。在PyQt5中,线程的终止操作应该由主线程来完成,这是比较安全可靠的做法。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值