pyqt 多线程出现问题

复制代码
import time

from PyQt5.Qt import *


class WorkThread(QThread):
    finished=pyqtSignal()
    def __init__(self):
        super(WorkThread, self).__init__()
        self.is_running = None

    def run(self):
        print('running')
        self.is_running = True
        while self.is_running:
            print('working....')
            time.sleep(1)
            self.finished.emit()

    def stop(self):
        self.is_running = False



class MainWindow(QMainWindow):
    def __init__(self):
        super(MainWindow, self).__init__()
        self.resize(600,500)
        self.work = WorkThread()
        self.work.setParent(self)
        self.work.destroyed.connect(lambda :print('thread is destoryed'))

        self.btn = QPushButton("start")
        self.btn2 = QPushButton("stop")

        layout = QVBoxLayout()
        layout.addWidget(self.btn)
        layout.addWidget(self.btn2)

        central_widget = QWidget()
        central_widget.setLayout(layout)

        self.setCentralWidget(central_widget)

        #slots
        self.btn.clicked.connect(self.start_thread)
        self.btn2.clicked.connect(self.stop_thread)

    def start_thread(self):
        self.work.start()

    def stop_thread(self):
        self.work.stop()

    def closeEvent(self, event) -> None:
        self.work.stop()

在运行时关闭窗口时会出错的原因是,当关闭窗口时,工作线程仍然在运行,并且在调用`self.work.stop()`时,工作线程已经被销毁,但是在`stop()`方法中仍然尝试设置`self.is_running`为False,这会导致AttributeError。

为了解决这个问题,你可以在关闭窗口时先停止工作线程,然后再关闭窗口。你可以在`closeEvent`方法中添加一个判断,如果工作线程正在运行,则先停止工作线程,然后再关闭窗口。代码如下:

```python

def closeEvent(self, event):

if self.work.isRunning():

self.work.stop()

self.work.wait() # 等待工作线程结束

event.accept()

```

这样,当关闭窗口时,会先停止工作线程并等待其结束,然后再关闭窗口,避免了出错的情况。

正确代码如下:

复制代码
import time

from PyQt5.Qt import *


class WorkThread(QThread):

    def __init__(self):
        super(WorkThread, self).__init__()
        self.is_running = None

    def run(self):
        print('running')
        self.is_running = True
        while self.is_running:
            print('working....')
            time.sleep(1)
          

    def stop(self):
        self.is_running = False



class MainWindow(QMainWindow):
    def __init__(self):
        super(MainWindow, self).__init__()
        self.resize(600,500)
        self.work = WorkThread()
        self.work.setParent(self)
        self.work.destroyed.connect(lambda :print('thread is destoryed'))

        self.btn = QPushButton("start")
        self.btn2 = QPushButton("stop")

        layout = QVBoxLayout()
        layout.addWidget(self.btn)
        layout.addWidget(self.btn2)

        central_widget = QWidget()
        central_widget.setLayout(layout)

        self.setCentralWidget(central_widget)

        #slots
        self.btn.clicked.connect(self.start_thread)
        self.btn2.clicked.connect(self.stop_thread)

    def start_thread(self):
        self.work.start()

    def stop_thread(self):
        self.work.stop()

    def closeEvent(self, event) -> None:
        if self.work.isRunning():
            self.work.stop()
            self.work.wait()
            event.accept()

import time

from PyQt5.Qt import *
import time

qum_1 = QMutex()
class Thread_1(QThread):

    def __init__(self):
        super(Thread_1, self).__init__()

    def run(self):
        qum_1.lock()
        values=[1,2,3,4,5]
        for i in values:
            print(i)
            time.sleep(0.5)
        qum_1.unlock()


class Thread_2(QThread):
    _signal = pyqtSignal()

    def __init__(self):
        super(Thread_2, self).__init__()

    def run(self):
        values = ["a","b","c","d","e"]
        for i in values:
            print(i)
            time.sleep(1)
        self._signal.emit()






class Window(QWidget):
    def __init__(self):
        super().__init__()
        self.setWindowTitle("的学习")
        self.resize(500,500)
        self.setup_ui()

        self.t=Thread_1()
        self.t2=Thread_2()
        self.t2._signal.connect(lambda :self.btn2.setEnabled(True))


    def setup_ui(self):

        self.btn = QPushButton('btn1',self)
        self.btn.move(10,20)
        self.btn.clicked.connect(self.btn_click)

        self.btn2 = QPushButton('btn2',self)
        self.btn.move(10,80)
        self.btn2.clicked.connect(self.btn2_click)


    def btn_click(self):
        self.t.start()

    def btn2_click(self):
        self.btn2.setEnabled(False)
        self.t2.start()





if __name__ == '__main__':
    import sys
    app=QApplication(sys.argv)

    win=Window()
    win.show()
    sys.exit(app.exec_())
相关推荐
IvanCodes4 小时前
Python 数据处理(十三):JSON、CSV 与数据序列化
开发语言·python
Patrick在香港5 小时前
Claude 工具调用返回空:8 次失败里只有 1 次状态码不对,其余全带 200
爬虫·python·api·claude·香港
Web3&Basketball5 小时前
CRM Agent 后训练实战:3 倍更少错误
python·架构·大模型·agent·推理
aramae5 小时前
MySQL复合查询(8)
java·c语言·开发语言·后端·算法
AIFQuant6 小时前
ETF行情API接入踩坑记:从报错到跑通的七个问题
python·金融·区块链·etf·基金
GPU实战笔记7 小时前
云端 Python 开发:JupyterLab 还是 VS Code Remote-SSH?
python·vs code·jupyterlab·remote-ssh·远程开发
狗狗狗狗狗乐啊8 小时前
搭一个 AI 对话工作台 AChat:从 0 到可用的完整记录(一)
python·react.js·ai编程
qq_2518364578 小时前
springboot vue3 开发实现 拼豆管理系统
java·开发语言·ai编程
白猫不黑8 小时前
Python实现简易Web弱口令爆破与防护方案
python·web安全·计算机·网络安全·黑客·信息安全·渗透测试
郑州光合科技余经理9 小时前
同城外卖小程序开发:下单成功后,后台导出能不能对上用户端状态
开发语言·前端·git·后端·uni-app·php·ai编程