pyqt5实现线程与弹窗功能

news2024/11/14 15:29:02

pyqt5实现线程与弹窗功能

效果图:

在这里插入图片描述

示例下载

点我下载
https://download.csdn.net/download/lm_is_dc/87982279

简介

Pyqt5线程使用 QThread, pyqtSignal, QMutex, QWaitCondition来实现,涉及到线程,锁,信号量,线程挂起,线程唤醒。
本文实现流程如下:
1、先设计UI;
2、把UI转py;
3、编写主函数
4、主函数流程:
4.1、创建QT窗口类、创建生产者类、消费者类
4.2、渲染画布、开启生产者线程、消费者线程
4.3、绑定触发事件,按钮点击、线程回调
4.4、标题设置成只读、设置指示灯颜色
4.5、点击开始按钮启动线程
4.6、点击暂停按钮,先弹出窗口,选择YES则挂起线程

1、UI设计

使用pycharm创建一个pyqt5项目,命名为QTThread_demo,界面如下:
在这里插入图片描述

2、ui转py

使用pyuic5把ui转成py文件,如图:
在这里插入图片描述
转成的thread_demo.py代码如下:

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

# Form implementation generated from reading ui file 'thread_demo.ui'
#
# Created by: PyQt5 UI code generator 5.15.4
#
# WARNING: Any manual changes made to this file will be lost when pyuic5 is
# run again.  Do not edit this file unless you know what you are doing.


from PyQt5 import QtCore, QtGui, QtWidgets


class Ui_MainWindow(object):
    def setupUi(self, MainWindow):
        MainWindow.setObjectName("MainWindow")
        MainWindow.resize(800, 600)
        self.centralwidget = QtWidgets.QWidget(MainWindow)
        self.centralwidget.setObjectName("centralwidget")
        self.title = QtWidgets.QTextEdit(self.centralwidget)
        self.title.setGeometry(QtCore.QRect(210, 0, 351, 51))
        self.title.setObjectName("title")
        self.producer_data = QtWidgets.QTextEdit(self.centralwidget)
        self.producer_data.setGeometry(QtCore.QRect(30, 160, 341, 251))
        self.producer_data.setObjectName("producer_data")
        self.label = QtWidgets.QLabel(self.centralwidget)
        self.label.setGeometry(QtCore.QRect(30, 140, 72, 15))
        self.label.setObjectName("label")
        self.label_2 = QtWidgets.QLabel(self.centralwidget)
        self.label_2.setGeometry(QtCore.QRect(400, 140, 72, 15))
        self.label_2.setObjectName("label_2")
        self.consumer_data = QtWidgets.QTextEdit(self.centralwidget)
        self.consumer_data.setGeometry(QtCore.QRect(400, 160, 341, 251))
        self.consumer_data.setObjectName("consumer_data")
        self.btn_start = QtWidgets.QPushButton(self.centralwidget)
        self.btn_start.setGeometry(QtCore.QRect(30, 80, 93, 28))
        self.btn_start.setObjectName("btn_start")
        self.btn_pause = QtWidgets.QPushButton(self.centralwidget)
        self.btn_pause.setGeometry(QtCore.QRect(180, 80, 93, 28))
        self.btn_pause.setObjectName("btn_pause")
        self.lamp = QtWidgets.QLabel(self.centralwidget)
        self.lamp.setGeometry(QtCore.QRect(400, 70, 72, 31))
        self.lamp.setObjectName("lamp")
        MainWindow.setCentralWidget(self.centralwidget)
        self.menubar = QtWidgets.QMenuBar(MainWindow)
        self.menubar.setGeometry(QtCore.QRect(0, 0, 800, 27))
        self.menubar.setObjectName("menubar")
        MainWindow.setMenuBar(self.menubar)
        self.statusbar = QtWidgets.QStatusBar(MainWindow)
        self.statusbar.setObjectName("statusbar")
        MainWindow.setStatusBar(self.statusbar)

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

    def retranslateUi(self, MainWindow):
        _translate = QtCore.QCoreApplication.translate
        MainWindow.setWindowTitle(_translate("MainWindow", "MainWindow"))
        self.title.setHtml(_translate("MainWindow", "<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.0//EN\" \"http://www.w3.org/TR/REC-html40/strict.dtd\">\n"
"<html><head><meta name=\"qrichtext\" content=\"1\" /><style type=\"text/css\">\n"
"p, li { white-space: pre-wrap; }\n"
"</style></head><body style=\" font-family:\'SimSun\'; font-size:9pt; font-weight:400; font-style:normal;\">\n"
"<p align=\"center\" style=\" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;\"><span style=\" font-size:18pt; font-weight:600; color:#0055ff;\">pyqt5线程与弹窗</span></p></body></html>"))
        self.label.setText(_translate("MainWindow", "生产者"))
        self.label_2.setText(_translate("MainWindow", "消费者"))
        self.btn_start.setText(_translate("MainWindow", "开始"))
        self.btn_pause.setText(_translate("MainWindow", "暂停"))
        self.lamp.setText(_translate("MainWindow", "指示灯"))

3、主程序

主程序main.py如下:

# !/usr/bin/python
# -*- coding: utf-8 -*-

"""
@contact: 微信 1257309054
@file: main.py
@time: 2023/7/1 23:55
@author: LDC
"""

import datetime
import json
import sys
import time

from PyQt5.QtCore import QThread, pyqtSignal, QMutex, QWaitCondition
from PyQt5.QtWidgets import QMainWindow, QApplication, QMessageBox

from thread_demo import Ui_MainWindow


class Window(QMainWindow, Ui_MainWindow):
    def __init__(self):
        super(QMainWindow, self).__init__()
        self.setup_ui()  # 渲染画布
        self.product_thread = ProductThread(self)  # 开启生产者线程
        self.consumer_thread = ConsumerThread(self)  # 开启消费者线程
        self.connect_signals()  # 绑定触发事件
        self.producer_data_list = []  # 生产者数据显示列表
        self.consumer_data_list = []  # 消费者数据显示列表
        self.status = 'init'  # 初始状态
        self.title.setReadOnly(True)  # 标题设置成只读
        self.set_lamp_color(self.status) # 设置指示灯颜色


    def setup_ui(self):
        self.setupUi(self)  # 渲染pyqt5界面
        # 设置只读,背景色为灰色
        style = 'background: #D3D3D3'
        self.producer_data.setStyleSheet(style)
        self.producer_data.setReadOnly(True)
        self.consumer_data.setStyleSheet(style)
        self.consumer_data.setReadOnly(True)

    def connect_signals(self):
        # 绑定触发事件
        self.btn_start.clicked.connect(self.btn_start_clicked)  # 开始按钮点击事件
        self.btn_pause.clicked.connect(self.btn_pause_clicked)  # 暂停按钮点击事件
        self.product_thread._signal_product.connect(self.product_threading_slot)  # 生产者线程回调函数
        self.consumer_thread._signal_consumer.connect(self.consumer_threading_slot)  # 消费者线程回调函数

    def btn_start_clicked(self):
        # 开始按钮
        if self.status == '0':
            return
        self.status = '0'
        self.lamp.setText(' 运行')
        self.set_lamp_color(self.status) # 设置指示灯为绿色
        if self.product_thread.is_pause:
            # 重新启动生产者线程
            self.product_thread.cond.wakeAll()
        else:
            self.product_thread.start()
        self.product_thread.is_pause = False

        if self.consumer_thread.is_pause:
            # 重新启动消费者线程
            self.consumer_thread.cond.wakeAll()
        else:
            self.consumer_thread.start()
        self.consumer_thread.is_pause = False



    def btn_pause_clicked(self):
        # 暂停按钮
        if self.status != '0':
            return
        # 先弹出窗口确认
        select = QMessageBox.warning(self, "暂停线程程序", "确定要暂停程序吗?", QMessageBox.Yes | QMessageBox.No, QMessageBox.Yes)
        if select == QMessageBox.Yes:
            self.status = '1'
            self.lamp.setText(' 暂停')
            self.set_lamp_color(self.status)
            self.product_thread.is_pause = True # 生产者线程进入暂停状态
            self.consumer_thread.is_pause = True # 消费者线程进入暂停状态

    def set_lamp_color(self, status):
        # 设置指示灯颜色 初始为灰色, 运行为绿色,暂停为红色
        color = {'init': '#0B610B', '0': '#9ACD32', '1': '#FF4000'}[status]
        style = """min-width: 44px; 
                       min-height: 44px;
                       max-width:44px; 
                       max-height: 44px;
                       border-radius: 22px;  
                       border:1px solid black;
                       background:{};
                       font-size:14px;
                       color:white
                    """.format(color)
        self.lamp.setStyleSheet(style)

    def product_threading_slot(self, data):
        # 生产者回调函数
        data = json.loads(data)
        if 'product_data' in data:
            self.producer_data_list.append(data['product_data'])

            self.producer_data.clear() # 先清空显示列表
            for d in self.producer_data_list:
                self.producer_data.append(d) # 把生产者数据显示出来

    def consumer_threading_slot(self, data):
        # 消费者回调函数
        data = json.loads(data)
        if 'consumer_data' in data:
            self.consumer_data_list.append(data['consumer_data'])
            if len(self.consumer_data_list) > 13:
                self.consumer_data_list.pop(0) # 消费者数据显示列表满13条就出栈
            self.consumer_data.clear() # 先清空显示列表
            for d in self.consumer_data_list:
                self.consumer_data.append(d) # 把消费者数据显示出来


# 生产者线程
class ProductThread(QThread):
    _signal_product = pyqtSignal(str)

    def __init__(self, parent=None):
        '''
        QWaitCondition()用于多线程同步,一个线程调用QWaitCondition.wait()阻塞等待,
        直到另外一个线程调用QWaitCondition.wake()唤醒才继续往下执行
        QMutex():是锁对象
        :param parent:
        '''
        super(ProductThread, self).__init__(parent)
        self.window = parent
        self.cond = QWaitCondition()
        self.qmut = QMutex()  # 线程锁
        self.is_pause = False  # 信号量

    def run(self):
        count = 1
        while 1:
            self.qmut.lock()
            if self.is_pause:
                self.cond.wait(self.qmut) # 线程挂起
            self.qmut.unlock()
            now = datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S')
            # 发送信号给槽函数,需要传送的是字符串
            self._signal_product.emit(json.dumps({'product_data': '{} 数据{}'.format(now, count)}))
            count += 1
            time.sleep(0.8)

# 消费者线程
class ConsumerThread(QThread):
    _signal_consumer = pyqtSignal(str)

    def __init__(self, parent=None):
        '''
        QWaitCondition()用于多线程同步,一个线程调用QWaitCondition.wait()阻塞等待,
        直到另外一个线程调用QWaitCondition.wake()唤醒才继续往下执行
        QMutex():是锁对象
        :param parent:
        '''
        super(ConsumerThread, self).__init__(parent)
        self.window = parent
        self.cond = QWaitCondition()
        self.qmut = QMutex()  # 线程锁
        self.is_pause = False  # 信号量

    def run(self):
        while 1:
            self.qmut.lock()
            if self.is_pause:
                self.cond.wait(self.qmut) # 线程挂起
            self.qmut.unlock()
            if self.window.producer_data_list:
                # 发送信号给槽函数,需要传送的是字符串
                self._signal_consumer.emit(json.dumps({'consumer_data': '消费了{}'.format(self.window.producer_data_list.pop(0))}))
                time.sleep(0.1)
            else:
                time.sleep(1)


if __name__ == '__main__':
    app = QApplication(sys.argv)
    mywindow = Window()
    mywindow.show()
    sys.exit(app.exec_())

4、运行效果图

运行:
在这里插入图片描述

暂停:
在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/708705.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

深入理解计算机系统(2)_计算机基本组成

深入理解计算机系统系列文章目录 第一章 计算机的基本组成 1. 内容概述 2. 计算机基本组成 第二章 计算机的指令和运算 第三章 处理器设计 第四章 存储器和IO系统 文章目录 深入理解计算机系统系列文章目录前言参考资料一、组成架构&#xff08;冯/图&#xff09;1. 组成架构2…

42. 接雨水

题目链接&#xff1a;力扣 解题思路&#xff1a;从左往右按列进行计算&#xff0c;依次计算每一列能够接到的雨水数量。对于当前列能够接到的雨水数量是由左右两边最高的两根柱子决定的&#xff0c;类似于木桶定律&#xff08;一只水桶能装多少水取决于它最短的那块木板&#x…

AI实践-定制你的专属简历-软件测试

简历对于找到一份理想的工作至关重要。但是&#xff0c;准备简历这一过程却让人感到头疼和繁琐&#xff0c;而且如何突出自己的优势&#xff0c;也是许多求职者遇到困惑。 chatgpt不会受到情感和个人喜好的影响&#xff0c;能够通过算法和数据分析为您编写最合适的简历。并且可…

目标检测算法-YOLOV5解析(附论文与源码)

目标检测算法-YOLOV5解析&#xff08;附论文与源码&#xff09;

数据结构 | 顺序二叉树

一、数据结构定义 1、顺序二叉树 /* 顺序二叉树 */ typedef char TreeType; typedef struct seqTree{int MAXNUM; // 最大元素个数int curNum; // 元素的个数TreeType nodelist[]; // 顺序二叉树节点存储 } *SeqTree; 本次代码中二叉树的结构如下图&#xff0c;用层次序列可…

【Python】字典

文章目录 一. 字典的创建二. 字典的操作1. 查找 key2. 新增键值对3. 删除键值对4. 遍历字典4.1 使用 for 循环遍历字典4.2 通过方法遍历字典keys() 获取到字典中所有 keyvalues() 获取到字典中的所以 valueitems 获取到字典中的所有键值对 三. 理解字典操作的效率 一. 字典的创…

Linux--打印文件内容:cat

cat是cater的简写 语法&#xff1a; cat [选项] [文件] 常用选项&#xff1a; -b 对非空输出行编号 -n 对输出的所有行编号 -s 不输出多行空行 示例&#xff1a; ①打印文件hello.c的内容 ②带行号打印文件hello.c的内容 ③输入什么&#xff0c;打印什么 ④输入重定向&…

讲座笔记:如何撰写高质量科技论文

1 论文总体思路 2 摘要 3 Intro 常见Introduction逻辑&#xff1a; 说明问题是什么&#xff1b;简单罗列前人工作&#xff1b;描述我们的工作。 说明问题是什么&#xff1b;目前最好的工作面临什么挑战&#xff1b;我们的方法能缓解上述挑战 3.1 段落写法 首先列出几句话 …

【 Linux】文件删除原理

文章目录 Linux文件删除原理文件的索引节点和链接文件删除的过程文件删除后是否能恢复 Linux文件删除原理 Linux是一个强大的操作系统&#xff0c;它提供了许多命令和工具来管理文件和目录。其中&#xff0c;最常用的命令之一就是rm&#xff0c;它可以用来删除不需要的文件或目…

Less简明教程

一.概述 Less是一种动态样式语言&#xff0c;它在CSS的基础上扩展了混合、嵌套、变量等实用功能。Less也是一种CSS预处理语言&#xff0c;less文件在经过less.js处理后&#xff0c;最终会生成.css文件&#xff0c;如下图所示&#xff1a; 1.动态样式语言的比较 动态样式语言主…

git push报错rejected:no-fast-forward

报错&#xff1a; 报错关键词&#xff1a; non-fast-forwardyour current branch is behindthe remote changes 即&#xff1a;不能快速前进、当前分支滞后、远端改变 原因&#xff1a; 这个分支下&#xff0c;别人提交了一些代码到远程仓库。对于这个改变&#xff0c;你没有…

SpringBoot+微信小程序在线订餐小程序系统 附带详细运行指导视频

文章目录 一、项目演示二、项目介绍三、运行截图四、主要代码 一、项目演示 项目演示地址&#xff1a; 视频地址 二、项目介绍 项目描述&#xff1a;这是一个基于SpringBoot微信小程序框架开发的在线订餐小程序系统。首先&#xff0c;这是一个前后端分离的项目&#xff0c;代…

什么是 Kubernetes 服务器端应用 (SSA)?

自 2021 年 8 月 v1.22 版本发布以来,服务器端应用 (SSA) 已在 Kubernetes 中普遍可用。这是一种声明式资源管理策略,可通过将命令逻辑移至kubectl apply服务器来改进 diff 计算并警告合并冲突。 本文将解释 SSA 的工作原理以及为什么它比以前的客户端应用 (CSA) 方法更受青…

Python3 面向对象 | 菜鸟教程(十六)

目录 一、面向对象技术简介 &#xff08;一&#xff09;类(Class) &#xff08;二&#xff09;方法 &#xff08;三&#xff09;类变量 &#xff08;四&#xff09;数据成员 &#xff08;五&#xff09;方法重写 &#xff08;六&#xff09;局部变量 &#xff08;七&am…

并发-抽象队列同步器AQS应用Lock详解

锁的膨胀是指synchronized原本是无锁态&#xff0c;当有一个线程调用时变为偏向锁&#xff0c;当有多个线程排队自旋等待锁时会升级为轻量锁&#xff0c;当线程等待时间太长时会升级为重量级锁&#xff0c;这就是锁的膨胀过程&#xff0c;且是不可逆的。 锁的粗化是指如果在一个…

【总结】1727- 前端开发中如何高效地模拟数据?

&#x1f449; 「文章推荐」 详细聊一聊 Vue3 动态组件深入浅出 Vue3 自定义指令6 个你必须明白 Vue3 的 ref 和 reactive 问题初中级前端必须掌握的 10 个 Vue 优化技巧分享 15 个 Vue3 全家桶开发的避坑经验 在开发和测试工作中&#xff0c;mock 数据非常实用。mock 数据是指…

基于值的深度强化学习算法

目录 DQN2013 —— Playing Atari with Deep Reinforcement LearningDQN2015 —— Human-level control through deep reinforcement learning引用文献 DQN2013 —— Playing Atari with Deep Reinforcement Learning 论文下载地址 论文介绍 该论文提出了一个基于卷积神经网络…

数字IC验证环境的创建

本文介绍了从一组可重用的验证组件中构建测试平台所需的步骤。UVM促进了重用&#xff0c;加速了测试平台构建的过程。 首先对测试平台集成者&#xff08;testbench integrator&#xff09;和测试编写者&#xff08;test writer &#xff09;进行区分&#xff0c;前者负责测试平…

【Java EE】-博客系统二(前后端分离)

作者&#xff1a;学Java的冬瓜 博客主页&#xff1a;☀冬瓜的主页&#x1f319; 专栏&#xff1a;【JavaEE】 分享: 徘徊着的 在路上的 你要走吗 易碎的 骄傲着 那也曾是我的模样 ——《平凡之路》 主要内容&#xff1a;显示用户信息、上传头像、新增博客、删除博客、修改博客…

Android:设计模式

文章参考来源1 文章参考来源2 文章参考来源3 MVC Model 数据来源&#xff0c;管理业务数据逻辑&#xff0c;读取数据等 View 视图 Controller 单例模式&#xff0c;处理业务逻辑&#xff0c;负责改变Model和View 经典的MVC架构是 用户点击View&#xff0c;View将用户输入转…