相关文章推荐
大气的扁豆  ·  PyQt5 ...·  6 天前    · 
一身肌肉的小虾米  ·  【Pyqt5】进度条QProgressBar ...·  6 天前    · 
彷徨的马铃薯  ·  pyqt5实现按钮添加背景图片以及背景图片的 ...·  6 天前    · 
英姿勃勃的烤面包  ·  你还在使用Dialog?赶紧把DialogF ...·  2 年前    · 
淡定的熊猫  ·  Django ...·  2 年前    · 
健壮的日光灯  ·  C#的利器LINQ-GroupJoin的應用 ...·  2 年前    · 
大力的饺子  ·  FFMpeg无损合并视频的多种方法 ...·  2 年前    · 
仗义的羽毛球  ·  django中实时获取当前在线人数 - 简书·  2 年前    · 
Code  ›  【Pyqt5】进度条QProgressBar的使用/多线程更新/按钮美化/图片编码/开机自启动开发者社区
pyqt5
https://cloud.tencent.com/developer/article/2022457
一身肌肉的小虾米
6 天前
zstar

【Pyqt5】进度条QProgressBar的使用/多线程更新/按钮美化/图片编码/开机自启动

腾讯云
开发者社区
文档 建议反馈 控制台
首页
学习
活动
专区
圈层
工具
MCP广场
文章/答案/技术大牛
发布
首页
学习
活动
专区
圈层
工具
MCP广场
返回腾讯云官网
zstar
首页
学习
活动
专区
圈层
工具
MCP广场
返回腾讯云官网
社区首页 > 专栏 > 【Pyqt5】进度条QProgressBar的使用/多线程更新/按钮美化/图片编码/开机自启动

【Pyqt5】进度条QProgressBar的使用/多线程更新/按钮美化/图片编码/开机自启动

作者头像
zstar
发布 于 2022-06-14 14:47:14
发布 于 2022-06-14 14:47:14
6.3K 0 0
代码可运行
举报
文章被收录于专栏: 往期博文 往期博文
运行总次数: 0
代码可运行

前言

诚如标题所见,我在使用Pyqt5进行开发时,先后遇到了上面几个问题。本篇博客就用来记录遇到问题/解决问题的过程,希望能给遇到相同问题的读者一些参考。

项目背景

我的项目是构建一个可视化的交互界面,通过界面上的按钮可调用后台的爬虫程序。因此,需要通过添加一个进度条来反映当前的爬取进度。

进度条

Pyqt5设有进度条控件QProgressBar, 官方文档 提供了一个按钮驱动定时器加载进度条的例子。本次应用和官方例程略有不同。

进度条创建与样式设定

首先创建一个进度条,设定位置,并用QSS设定样式。

代码语言: javascript
代码 运行次数: 0
运行
复制
self.pb = QtWidgets.QProgressBar(self.centralwidget)
self.pb.setGeometry(QtCore.QRect(230, 690, 1021, 41))
self.pb.setStyleSheet("QProgressBar {border: 2px solid grey; border-radius: 5px; background-color: #FFFFFF; text-align:center; font-size:20px}")

这里的样式主要是对进度条外框进行修改,默认情况进度字体显示在进度条右侧,设置后将字体居中在进度条内,进度条则使用默认情况的绿色进度条,自带了动态加载光效,效果如图所示。

之后,设置进度条的范围[0,100],并将进度条在默认情况下进行隐藏。

代码语言: javascript
代码 运行次数: 0
运行
复制
self.pb.setRange(0, 100)
self.pb.hide() 

进度条更新

使用pyqt5独特的信号与槽函数可进行进度条的更新。进度条设置函数 setvalue() 由于进度条总长度是未知的,因此首先在进度条开始更新之前,需要先获取总任务量的数据,然后将完成任务量/总任务量,映射到[0,100]的区间内进行更新。 此外,还需要获取一个信号来标记是否结束,如果结束,则立刻将进度条设置为100%,同时弹出提示信息(本程序是弹出一个提示框)

定义两个信号: progressBarValue :用来回传当前换算后的进度数值 signal_done :用来回传完成标记(由于pyqtSignal无法回传bool型数据,采用int型来进行区分。0表示未完成,1表示完成)

对应两个槽函数: callback :接收progressBarValue信号 callback_done :接收signal_done信号

更新逻辑:初始进度条为隐藏状态,点击按钮,进度条进行显示,并设定初始值为0。当所有链接获取完之后,进度条开始逐渐更新(每间隔十个数据进行一次进度条更新)。若全部爬取完成(signal_done发送1信号),进度条填满,并弹出提示框。 核心代码如下:

代码语言: javascript
代码 运行次数: 0
运行
复制
 # 两个参数初始化
 self.pb.setValue(0)  # 设置进度条为0
 self.is_done = 0  # 设置完成标记 完成/未完成 1/0
 self.progressBarValue.connect(self.callback)
 self.signal_done.connect(self.callback_done)
# 回传进度条参数
def callback(self, i):
    self.pb.setValue(i)
# 回传结束信号
def callback_done(self, i):
    self.is_done = i
    if self.is_done == 1:
        self.messageDialog1()
progressBarValue = pyqtSignal(int)  # 更新进度条
signal_done = pyqtSignal(int)  # 是否结束信号
Linklist_sum = self.pro_name.get_crawler_link()
length = len(Linklist_sum)
for start in range(0, length, 10):
	self.pro_name.run_crawlertask(start, Linklist_sum)
	self.progressBarValue.emit(int(start / length * 100))  # 发送进度条的值信号
self.signal_done.emit(1)  # 发送结束信号
def messageDialog1(self):
    msg_box = QMessageBox(QMessageBox.Information, '通知', '信息爬取已结束')
    self.pb.setValue(100)  # 如果爬取成功
    msg_box.exec_()

多线程更新

直接将进度条更新的程序段和要调用的程序段放在一起会出现一个问题。当调用程序段运行时,qt界面会卡住不动,造成“假死”现象。 因此,要解决这个问题,就要引入多线程。将后台程序放入到一个子线程中运行,同时将数值传递给主线程,在主线程中进行UI的更新。 修改后的进度条更新程序段如下:

代码语言: javascript
代码 运行次数: 0
运行
复制
# 封装调用子线程执行程序name
def run_py(self, name):
    # 两个参数初始化
    self.pb.setValue(0)  # 设置进度条为0
    self.is_done = 0  # 设置完成标记 完成/未完成 1/0
    self.thread_1 = Runthread(pro_name=name)
    self.thread_1.progressBarValue.connect(self.callback)
    self.thread_1.signal_done.connect(self.callback_done)
    self.thread_1.start()
# 回传进度条参数
def callback(self, i):
    self.pb.setValue(i)
# 回传结束信号
def callback_done(self, i):
    self.is_done = i
    if self.is_done == 1:
        self.messageDialog1()
# Runthread子线程
class Runthread(QThread):
    progressBarValue = pyqtSignal(int)  # 更新进度条
    signal_done = pyqtSignal(int)  # 是否结束信号
    def __init__(self, pro_name):
        super(Runthread, self).__init__()
        self.pro_name = pro_name
    def run(self):
        Linklist_sum = self.pro_name.get_crawler_link()
        length = len(Linklist_sum)
        for start in range(0, length, 10):
            self.pro_name.run_crawlertask(start, Linklist_sum)
            self.progressBarValue.emit(int(start / length * 100))  # 发送进度条的值信号
        self.signal_done.emit(1)  # 发送结束信号

按钮美化

甲方要求我做一个科技风格的按钮,然而没给我设计贴图,于是我采用QSS的qlineargradient实现渐变填充,先看效果。 常规状态: 鼠标悬浮状态:边框变红 鼠标按下状态:字体下沉 相关代码:

代码语言: javascript
代码 运行次数: 0
运行
复制
font = QtGui.QFont()
font.setFamily("方正粗黑宋简体")
font.setPointSize(18)
self.pushButton.setFont(font)
self.pushButton.setObjectName("pushButton")
self.pushButton.setStyleSheet("QPushButton{background:qlineargradient(spread:reflect, x1:0, y1:1, x2:0, y2:0, "
                             "stop:0 #0a4a83, stop:0.5 #186e99, stop:1 #239cd8);"
                             "border:2px solid qlineargradient(spread:pad, x1:1, y1:1, x2:1, y2:0,"
                             "stop:0 #002aff, stop:0.5 #00aeff, stop:1 #00e6fc); border-radius:1px; "
                             "color:#d0f2f5} "
                             "QPushButton:hover:!pressed {border:1px solid #f8878f;}"
                             "QPushButton:pressed {padding-left:6px;padding-top:6px;border:1px solid #f8878f;}")

另外提供另一种美化示例: 相关代码

代码语言: javascript
代码 运行次数: 0
运行
复制
self.pushButton.setStyleSheet("QPushButton{background:qlineargradient(spread:pad, x1:0, y1:1, x2:0, y2:0, "
                              "stop:0 #00ffff, stop:0.5 #1D2B56, stop:1 "
                              "#00ffff);border:0px;border-radius:1px;color:white;}")

选择框美化

顺带一提选择框美化,我的界面风格是暗黑系的,有一个开源的QSS风格 qdarkstyle 可以直接套用。

代码语言: javascript
代码 运行次数: 0
运行
复制
import qdarkstyle
self.comboBox = QtWidgets.QComboBox(self.centralwidget)
self.comboBox.setStyleSheet(qdarkstyle.load_stylesheet_pyqt5())  # 设置暗黑风格

当然,也可以全局配置该风格。

代码语言: javascript
代码 运行次数: 0
运行
复制
app.setStyleSheet(qdarkstyle.load_stylesheet_pyqt5())

但是我觉得该风格的按钮设计没上面自己设计的靓眼,因此局部应用了该风格。

图片编码

如果在pyqt中的界面使用了贴图,在用pyinstaller打包成exe文件后,如果贴图和exe文件不在同一路径下,则会无法显示。 为了解决这一问题,可以使用pyqt自带的 Pyqrc 将图片资源编码成二进制数据,从而能够一起打包进exe文件。

首先建立文件 img.qrc 将用到的图片写进去,比如,我用到了四张png图片。

代码语言: javascript
代码 运行次数: 0
运行
复制
<RCC>
  <qresource prefix="png">
    <file>images/title_bg.png</file>
    <file>images/button_bg.png</file>
    <file>images/bg.png</file>
    <file>images/2.png</file>
  </qresource>
</RCC>

之后,在pycharm中配置Pyqrc,配置方法可以参见这篇博客 PyCharm中配置与PyQT5相关的External tools 然后,就能在pycharm中快速使用pyqrc进行转换。 转换之后,会生成img_rc.py文件。 在引用贴图的py文件中,引入该文件即可。

代码语言: javascript
代码 运行次数: 0
运行
复制
import img_rc

再次进行打包,生成的exe即包含图片信息。

开机自启动

exe文件完成了,甲方又给我提了最后一条需求,要求能够设置开机自启动。 这里,我提供两种方法。

添加注册表方法

第一种方式稍微复杂一些,通过python程序,将生成的exe添加到系统的启动注册表内。

代码语言: javascript
代码 运行次数: 0
运行
复制
import win32api
import win32con
import sys
import os
sys.setrecursionlimit(1000000)
name = 'auto_run'
cur_path = os.getcwd()
path = cur_path + '\\' '你的程序名.exe'
KeyName = r'Software\\Microsoft\\Windows\\CurrentVersion\\Run'
    key = win32api.RegOpenKey(win32con.HKEY_CURRENT_USER, KeyName, 0, win32con.KEY_ALL_ACCESS)
    win32api.RegSetValueEx(key, name, 0, win32con.REG_SZ, path)
    win32api.RegCloseKey(key)
except:
    print('error!')
print('success!')

运行之后输出success即添加成功。 打开系统注册表和任务管理器,可以看到添加的内容。

 
推荐文章
大气的扁豆  ·  PyQt5 在按钮上添加图片_pyqt5在按钮上添加图片
6 天前
一身肌肉的小虾米  ·  【Pyqt5】进度条QProgressBar的使用/多线程更新/按钮美化/图片编码/开机自启动开发者社区
6 天前
彷徨的马铃薯  ·  pyqt5实现按钮添加背景图片以及背景图片的切换_pyqt5添加背景图片
6 天前
英姿勃勃的烤面包  ·  你还在使用Dialog?赶紧把DialogFragment用起来-腾讯云开发者社区-腾讯云
2 年前
淡定的熊猫  ·  Django Web图书管理系统数据库设计及源码实现 - 墨天轮
2 年前
健壮的日光灯  ·  C#的利器LINQ-GroupJoin的應用 - iT 邦幫忙::一起幫忙解決難題,拯救 IT 人的一天
2 年前
大力的饺子  ·  FFMpeg无损合并视频的多种方法 python_51CTO博客_ffmpeg 合并视频
2 年前
仗义的羽毛球  ·  django中实时获取当前在线人数 - 简书
2 年前
今天看啥   ·   Py中国   ·   codingpro   ·   小百科   ·   link之家   ·   卧龙AI搜索
删除内容请联系邮箱 2879853325@qq.com
Code - 代码工具平台
© 2024 ~ 沪ICP备11025650号