前言

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

项目背景

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

进度条

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

进度条创建与样式设定

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

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],并将进度条在默认情况下进行隐藏。

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信号),进度条填满,并弹出提示框。
核心代码如下:

 # 两个参数初始化self.pb.setValue(0)  # 设置进度条为0self.is_done = 0  # 设置完成标记 完成/未完成 1/0self.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 = iif 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的更新。
修改后的进度条更新程序段如下:

# 封装调用子线程执行程序name
def run_py(self, name):# 两个参数初始化self.pb.setValue(0)  # 设置进度条为0self.is_done = 0  # 设置完成标记 完成/未完成 1/0self.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 = iif 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_namedef 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实现渐变填充,先看效果。
常规状态:

鼠标悬浮状态:边框变红

鼠标按下状态:字体下沉

相关代码:

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;}")

另外提供另一种美化示例:

相关代码

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可以直接套用。

import qdarkstyleself.comboBox = QtWidgets.QComboBox(self.centralwidget)
self.comboBox.setStyleSheet(qdarkstyle.load_stylesheet_pyqt5())  # 设置暗黑风格

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

app.setStyleSheet(qdarkstyle.load_stylesheet_pyqt5())

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

图片编码

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

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

<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文件中,引入该文件即可。

import img_rc

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

开机自启动

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

添加注册表方法

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

import win32api
import win32con
import sys
import ossys.setrecursionlimit(1000000)
name = 'auto_run'
cur_path = os.getcwd()
path = cur_path + '\\' '你的程序名.exe'
KeyName = r'Software\\Microsoft\\Windows\\CurrentVersion\\Run'try: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即添加成功。
打开系统注册表和任务管理器,可以看到添加的内容。

如果需要关闭,在任务管理器内设置禁用即可。

bat脚本方法

正常来说,上面那种方法能够实现开机自启动,但是如果exe有个功能是打开当前程序文件夹,该方法会出现问题。开机启动后,打开当前文件夹会诡异地定位到C盘的system32文件夹里。
因此,有了下面这个方式,不仅可以解决这个问题,并且更加方便。

Windows在C盘中提供了一个启动文件夹(win+R:输入shell:startup即可进入),程序放入该文件夹中后,开机就能自动启动程序。由于我的程序涉及打开当前文件夹的操作,因此不能直接将程序放进去,而是将程序的快捷方式放进去。

首先创建快捷方式,命名为"shortcut"。
然后创建bat脚本,输入

xcopy "shortcut.lnk" "C:\Users\%username%\AppData\Roaming\Microsoft\Windows\Start Menu\Programs\Startup" /Y

这里使用xcopy命令进行快捷方式的复制,其中/Y表示目标存在同名文件的情况取消提示以确认要覆盖。xcopy的更多参数设置可参考批处理(bat)xcopy详解
另外,创建快捷方式后的扩展名lnk不会直接显示,但在写脚本中需要进行补充。
如果快捷方式中有中文,需要将bat脚本内容改成ANSI编码,修改方式可参考Bat批处理命令执行中文路径方法。

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

  1. python进度条 pyqt_Python高级进阶#015 pyqt5进度条QProgressBar结合使用qbasictimer

    本期GUI界面,我们继续学习新的控件Qprogressbar. 知识回顾 1.滑动控件qslider 控件设置的关键:设置最大值.最小值,绝对范围. 2.核心类库QtCore,枚举类Qt 核心枚举类的 ...

  2. 【Python笔记】pyqt5进度条-多线程图像分块处理防止窗体卡顿

    目录 主要功能 环境配置 实现过程 1.设计ui 主界面 弹出框 窗体文件 2.主体实现 打开文件 计算函数 代码附录 title.ui titleok.ui title.py titleok.py ...

  3. python3.6进度条_Python实现下载界面(带进度条,断点续传,多线程多任务下载等)...

    开发环境: Windows 7 64位,Python 3.6.2 实现功能: 进度条,下载速度和下载进度的显示,断点续传(暂停继续下载功能),取消下载等功能 下载界面,如图所示 点击'新建任务',弹出 ...

  4. 可拖动的进度条_TIM iOS版重大更新:支持语音进度条拖动和暂停

    3月30日消息,今日腾讯正式发布了QQ办公简洁版TIM iOS版2.5.6的更新.此次更新中,腾讯在TIM中新增了许多实用性功能,比如大家期待已久的语音消息支持进度前后拖动和暂停.微信账号登录等. 在 ...

  5. PyQt5 --- 进度条拖动点击视频播放

    最近学习pyqt5,做一个视频播放器,网上找了很多资料都没有关于python方面的视频进度条拖动点击的方法,几乎都是Qt的.对相关资料的查阅,发现开发过程其实差不多,为此做一下相关的总结. 一.UI的 ...

  6. win10重置进度条不动了_win10系统更新进度条不动了的解决方法

    很多小伙伴都遇到过win10系统更新进度条不动了的困惑吧,一些朋友看过网上零散的win10系统更新进度条不动了的处理方法,并没有完完全全明白win10系统更新进度条不动了是如何解决的,今天小编准备了简 ...

  7. (已解决)(Jupyter notebook)中的tqdm进度条不是在一行更新并显示而是一直滚动往下输出

    原因 上次使用tqdm的时候,其还没有执行结束,你就中断了. 解决办法 最粗暴的当然对这个notebook进行shutdown喽,销毁所有对象(注意和重启服务器的区别). 更加标准的解决办法:采用创建 ...

  8. 【pyqt5学习】——进度条progressBar

    # 进度条 self.progressBar.setValue(0) # 设置进度条的最小值 self.progressBar.setMaximum(100) # 设置进度条的最大值 # 设置进度条当 ...

  9. 由一个进度条更新所引发的思考

    事情的起因 事情是这样子的,我前阵子在Github上开源了一个Android全量版本更新的框架XUpdate, 受到了大家一致的好评. 但是随着使用者基数的不断增大,中间也暴露了很多问题,其中问的最多 ...

最新文章

  1. python【数据结构与算法】倍增思想
  2. 字符串表示的大整数相乘
  3. MyBatis 架构分层与模块划分
  4. ubuntu 电源按钮操作_Ubuntu电脑操作基础:桌面背景,屏保和电源
  5. iphone模拟器快捷键使用
  6. 文件操作相关的系统函数
  7. 第十二届交博会正式启动 百度智慧交管解决方案助城市开启智能交通新纪元
  8. php重定向mysql_使用.php文件生成MySQL转储
  9. P1066 2^k进制数
  10. Abaqus2019+VS2019+Fortran子程序安装关联全过程亲测有效
  11. MySQL可视化工具连不上或mysql启动不了
  12. 二阶系统阶跃响应实验_二阶系统的阶跃响应实验报告
  13. 系统分析师考试大纲2009
  14. IV-18(前苏联ИВ-18)荧光管电子钟【Energy Pillar.能量柱】
  15. 一台计算机多个屏幕,一台电脑多个显示器,屏幕远程控制
  16. CS229 机器学习课程复习材料-线性代数
  17. 【Vue 4 笔记 】(一)
  18. 猿创征文|我的Go成长之路道阻且长
  19. Android 获取 签名哈希值 sha1值
  20. 基于MATLAB App Designer的串口RS485 Modbus上位机

热门文章

  1. java单词倒序输出_Java实现单词倒序输出
  2. python 单词拆分_python - 如何拆分没有空格的文本为单词列表?将组合单词拆分开...
  3. 标准差 php,PHP基于方差和标准差计算学生成绩的稳定性示例
  4. win电脑被安装垃圾软件后在注册表哪里卸载?
  5. 【项目】视频点播系统
  6. 关于 Word2Vec 使用时遇到的一系列问题。
  7. java中的identity_java – 有没有办法使用Hibernate的IDENTITY ID生...
  8. 一篇掌握SpringBoot+SpringCache+Redis超详细实例
  9. 51单片机(十七)红外遥控(外部中断)
  10. LifeSize针对互联网行业的高清视频会议协作解决方案