zoukankan      html  css  js  c++  java
  • pyqt5学习之QThread

           pyqt的线程的使用非常简单-建立一个自定义的类(如thread),使它继承自QThread,并实现其run()方法即可; 在使用线程时可以直接得到thread实例,调用其start()函数即可启动线程。线程启动后,会自动调用其实现run方法,该方法就是线程的执行函数。

           业务的线程任务就写在run()函数中,当run()退出之后线程基本就结束了。

    常用方法:strat():启动线程

              wait():阻值线程

              sleep():强制当前线程睡眠毫秒

    常用信号:started:在开始执行run()函数前,从相关线程发射此信号

         finished:当程序完成业务逻辑时,从相关线程发射此信号

    步骤:1.建立一个线程实例

          2.在主线程类创建一个属性连接子线程

          3.使用strat()开始子线程

    from PyQt5.QtCore import *
    from PyQt5.Qt import *
    from PyQt5.QtGui import *
    import sys
    import cgitb
    sys.excepthook = cgitb.Hook(1, None, 5, sys.stderr, 'text')
    class mythread(QThread):  # 步骤1.创建一个线程实例
        mysignal = pyqtSignal(tuple)  # 创建一个自定义信号,元组参数
    
        def __init__(self):
            super(mythread, self).__init__()
    
    
        def run(self):
            a = (1, 2)
            self.mysignal.emit(a)  # 发射自定义信号
    
    class Window(QWidget):
        def __init__(self):
            super(Window, self).__init__()
            self.setWindowTitle('信号传输')
            self.resize(500,500)
            self.move(50,50)
            self.setup_ui()
    
            self.my_thread = mythread()  # 步骤2. 主线程连接子线
            self.my_thread.mysignal.connect(self.zhi)  # 自定义信号连接
            self.my_thread.start()   #  步骤3 子线程开始执行run函数
    
        def setup_ui(self):
            self.line1 = QLineEdit(self)
            self.line1.move(0,0)
            self.line1.resize(50,50)
    
            self.line2 = QLineEdit(self)
            self.line2.move(50, 50)
            self.line2.resize(50, 50)
    
    
        def zhi(self, zhi):
            a, b = zhi
            self.line1.setText(str(a))
            self.line2.setText(str(b))
    if __name__ == '__main__':
    
        app = QApplication(sys.argv)
    
        window = Window()
        window.show()
        sys.exit(app.exec_())
    QThread

     UI主线程传递数据给子线程:

    from PyQt5.QtCore import *
    from PyQt5.Qt import *
    from PyQt5.QtGui import *
    import sys
    import cgitb
    sys.excepthook = cgitb.Hook(1, None, 5, sys.stderr, 'text')
    class mythread(QThread):  # 步骤1.创建一个线程实例
        mysignal = pyqtSignal(tuple)  # 创建一个自定义信号,元组参数
    
        def __init__(self, a):  #通过初始化赋值的方式实现UI主线程传递值给子线程
            super(mythread, self).__init__()
            self.a = a
    
        def run(self):
            a = (1, 2)
            self.mysignal.emit(a)  # 发射自定义信号
    
    class Window(QWidget):
        mysignal2 = pyqtSignal(tuple)
        def __init__(self):
            super(Window, self).__init__()
            self.setWindowTitle('信号传输')
            self.resize(500,500)
            self.move(50,50)
            self.setup_ui()
    
    
    
        def setup_ui(self):
            self.line1 = QLineEdit(self)
            self.line1.move(0,0)
            self.line1.resize(50,50)
    
            self.line2 = QLineEdit(self)
            self.line2.move(50, 50)
            self.line2.resize(50, 50)
    
            self.btn = QPushButton('按钮',self)
            self.btn.resize(50,50)
            self.btn.move(150,0)
            self.btn.clicked.connect(self.cao1)
    
    
    
        def zhi(self, zhi):
            a, b = zhi
            self.line1.setText(str(a))
            self.line2.setText(str(b))
    
        def cao1(self):
            self.my_thread = mythread(1)  # 步骤2. 主线程连接子线,同时传递一个值给子线程
            self.my_thread.mysignal.connect(self.zhi)  # 自定义信号连接
            self.my_thread.start()  # 步骤3 子线程开始执行run函数
    
    
    
    if __name__ == '__main__':
    
        app = QApplication(sys.argv)
    
        window = Window()
        window.show()
        sys.exit(app.exec_())
    View Code

     moveToThread:在主线程中将程序送到子线程中运行

    # -*- coding: utf-8 -*-
    import sys
    from PyQt5.QtWidgets import *
    from PyQt5.QtCore import *
    import time
    import cgitb
    sys.excepthook = cgitb.Hook(1, None, 5, sys.stderr, 'text')
    
    # 需要工作在子线程的程序继承的类必须是QObject
    class Work(QObject):
        count = int(0)
        count_signal = pyqtSignal(int)
    
        def __init__(self, parent=None):
            super(Work, self).__init__(parent)
            self.run = True
    
        def work(self):
            print('current id', int(QThread.currentThreadId()))
            self.run = True
            while self.run:
                # print(str(self.count))
                self.count += 1
                self.count_signal.emit(self.count)
                time.sleep(1)
    
        def work_stop(self):
            self.run = False
    
    class Window(QWidget):
        def __init__(self):
            super(Window, self).__init__()
            self.setup_ui()
    
            print('main id', int(QThread.currentThreadId()))
    
            self.thread = QThread()  # 这里设定的一个多线程是一个管理者
            self.worker = Work()  # 不能有父类
            self.worker.count_signal.connect(self.flush)
    
            self.worker.moveToThread(self.thread)  # 将耗时的类在设定的子线程中运行
            self.thread.finished.connect(self.finished)
    
        def setup_ui(self):
            self.setWindowTitle('movetothread')
            self.resize(500,500)
    
            self.btn1 = QPushButton('开始', self)
            self.btn1.resize(50,50)
            self.btn1.clicked.connect(self.workStart)
    
            self.btn2 = QPushButton('结束',self)
            self.btn2.resize(50, 50)
            self.btn2.move(0, 50)
            self.btn2.clicked.connect(self.workStop)
    
            self.label = QLabel(self)
            self.label.resize(100,100)
            self.label.move(100, 100)
    
        def flush(self, count):
            self.label.setText(str(count))
    
        def workStart(self):
            print('开始')
            self.btn1.setEnabled(False)
            self.thread.start()
            self.thread.started.connect(self.worker.work)  # 当子线程启动时,调用需要运行类的方法
    
        def workStop(self):
            print('结束')
            self.worker.work_stop()
            self.thread.quit()
    
        def finished(self):
            print('finish')
            self.btn1.setEnabled(True)
    
    if __name__ == '__main__':
        app = QApplication(sys.argv)
        w = Window()
        w.show()
        sys.exit(app.exec_())
    View Code

    线程休眠唤醒

    from PyQt5.QtCore import QThread, QWaitCondition, QMutex, pyqtSignal
    from PyQt5.QtWidgets import QWidget, QVBoxLayout, QPushButton, QProgressBar
    
    class Thread(QThread):
        valuechange = pyqtSignal(int)
    
        def __init__(self, *args, **kwargs):
            super(Thread, self).__init__(*args, **kwargs)
            self._isPause = False
            self._value = 0
            self.cond = QWaitCondition()
            # QWaitCondition用于多线程的同步,一个线程调用QWaitCondition.wait()阻塞等待,直到另一个线程调用QWaitCondition.wake()唤醒才继续往下执行.
            self.mutex = QMutex()  # 互斥锁
    
        def pause(self):
            self._isPause = True
    
        def resume(self):
            self._isPause = False
            self.cond.wakeAll()  # 唤醒所有线程
    
        def run(self):
            while 1:
                self.mutex.lock() # 加锁只能一个线程使用
                if self._isPause:
                    self.cond.wait(self.mutex)
                    # QWaitCondition.wait()在使用时必须传入一个上锁的QMutex对象
                    # 在wait()执行过程中,mutex一直保持上锁状态,直到调用操作系统的wait_block在阻塞的一瞬间把mutex解锁(严格说
                    # 来应该是原子操作,即系统能保证在真正执行阻塞等待指令时才解锁).另一线程唤醒后,wait()函数将在第一时间重新给
                    # mutex上锁,直到显示调用mutex.unlock()解锁.
                    # 由此可见,通过mutex把有严格时序要求的代码保护起来,同时把wakeAll()也用同一个mutex保护起来,这样能保证:
                    # 一定先有wait(),再有wakeAll(),不管什么情况,都能保证这先后关系,而不至于摆乌龙.
                if self._value >100:
                    self._value = 0
                self._value += 1
                self.valuechange.emit(self._value)
                self.msleep(100)
                self.mutex.unlock() # 解锁给接下来的线程使用
    
    class Window(QWidget):
        def __init__(self, *args, **kwargs):
            super(Window, self).__init__(*args, **kwargs)
            layout = QVBoxLayout(self)
            self.progressBar = QProgressBar(self)
            layout.addWidget(self.progressBar)
            layout.addWidget(QPushButton('休眠', self, clicked=self.doWait))
            layout.addWidget(QPushButton('唤醒', self, clicked=self.doWake))
    
            self.t = Thread(self)
            self.t.valuechange.connect(self.progressBar.setValue)
            self.t.start()
    
        def doWait(self):
            self.t.pause()
    
        def doWake(self):
            self.t.resume()
    
    if __name__ == '__main__':
        import sys
        import cgitb
        sys.excepthook = cgitb.enable(1, None, 5, '')
        from PyQt5.QtWidgets import QApplication
        app = QApplication(sys.argv)
        w = Window()
        w.show()
        sys.exit(app.exec_())
    View Code

     线程挂起和唤醒

    #!/usr/bin/env python
    # -*- coding: utf-8 -*-
    import ctypes
    
    from PyQt5.QtCore import QThread, pyqtSignal
    from PyQt5.QtWidgets import QWidget, QVBoxLayout, QProgressBar, QPushButton
    import win32con
    from win32process import SuspendThread, ResumeThread
    
    class Worker(QThread):
    
        valueChanged = pyqtSignal(int)  # 值变化信号
        handle = -1
    
        def run(self):
            try:
                self.handle = ctypes.windll.kernel32.OpenThread(
                    win32con.PROCESS_ALL_ACCESS, False, int(QThread.currentThreadId()))
                # 利用该方法得到线程的句柄,然后就可以通过SuspendThread和ResumeThread两个函数对其进行挂起与恢复
            except Exception as e:
                print('get thread handle failed', e)
            print('thread id', int(QThread.currentThreadId()))
            for i in range(1, 101):
                print('value', i)
                self.valueChanged.emit(i)
                QThread.sleep(1)
    
    
    class Window(QWidget):
    
        def __init__(self, *args, **kwargs):
            super(Window, self).__init__(*args, **kwargs)
            layout = QVBoxLayout(self)
            self.progressBar = QProgressBar(self)
            self.progressBar.setRange(0, 100)
            layout.addWidget(self.progressBar)
    
            self.startButton = QPushButton('开启线程', self, clicked=self.onStart)
            layout.addWidget(self.startButton)
    
            self.suspendButton = QPushButton(
                '挂起线程', self, clicked=self.onSuspendThread, enabled=False)
            layout.addWidget(self.suspendButton)
    
            self.resumeButton = QPushButton(
                '恢复线程', self, clicked=self.onResumeThread, enabled=False)
            layout.addWidget(self.resumeButton)
    
            self.stopButton = QPushButton(
                '终止线程', self, clicked=self.onStopThread, enabled=False)
            layout.addWidget(self.stopButton)
    
            # 当前线程id
            print('main id', int(QThread.currentThreadId()))
    
            # 子线程
            self._thread = Worker(self)
            self._thread.finished.connect(self._thread.deleteLater)
            self._thread.valueChanged.connect(self.progressBar.setValue)
    
        def onStart(self):
            print('main id', int(QThread.currentThreadId()))
            self._thread.start()  # 启动线程
            self.startButton.setEnabled(False)
            self.suspendButton.setEnabled(True)
            self.stopButton.setEnabled(True)
    
        def onSuspendThread(self):
            if self._thread.handle == -1:
                return print('handle is wrong')
            ret = SuspendThread(self._thread.handle)
            print('挂起线程', self._thread.handle, ret)
            self.suspendButton.setEnabled(False)
            self.resumeButton.setEnabled(True)
    
        def onResumeThread(self):
            if self._thread.handle == -1:
                return print('handle is wrong')
            ret = ResumeThread(self._thread.handle)
            print('恢复线程', self._thread.handle, ret)
            self.suspendButton.setEnabled(True)
            self.resumeButton.setEnabled(False)
    
        def onStopThread(self):
            self.startButton.setEnabled(False)
            self.suspendButton.setEnabled(False)
            self.resumeButton.setEnabled(False)
            ret = ctypes.windll.kernel32.TerminateThread(
                self._thread.handle, 0)
            # 终止线程,不推荐
            print('终止线程', self._thread.handle, ret)
            self.stopButton.setEnabled(False)
    
        def closeEvent(self, event):
            if self._thread.isRunning():
                self._thread.quit()
                # 强制
                # self._thread.terminate()
            del self._thread
            super(Window, self).closeEvent(event)
    
    
    if __name__ == '__main__':
        import sys
        import os
        print('pid', os.getpid())
        from PyQt5.QtWidgets import QApplication
        app = QApplication(sys.argv)
        w = Window()
        w.show()
        sys.exit(app.exec_())
    View Code

    线程的休眠唤醒用的是python线程的方法;线程的挂起和唤醒用的是C++线程方法

  • 相关阅读:
    软件工程个人作业01
    个人冲刺——(五)
    个人冲刺——(四)
    个人冲刺——(三)
    个人冲刺——(二)
    个人冲刺——(一)
    单词统计
    第十周学习总结
    第九周学习总结
    用户模板场景分析
  • 原文地址:https://www.cnblogs.com/mosewumo/p/12486228.html
Copyright © 2011-2022 走看看