news 2026/9/8 18:00:52

PyQt5 实现 Windows EXE 程序在线更新(自动下载 + 覆盖升级)

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
PyQt5 实现 Windows EXE 程序在线更新(自动下载 + 覆盖升级)

一、前言

在使用PyQt5 + PyInstaller开发 Windows 桌面工具时,一个非常现实的问题是:

👉程序如何自动检测新版本,并完成在线升级?

本文基于一个真实可用、已落地的更新方案,实现了:

  • ✅ 远程版本号检测
  • ✅ 语义化版本对比
  • ✅ 更新提示弹窗
  • ✅ 子线程下载更新包
  • ✅ 实时下载进度条
  • ✅ ZIP 解压
  • ✅ EXE 自动替换
  • ✅ 旧版本自动备份
  • ✅ 更新完成后安全退出

非常适合工具类 / 内部系统 / 单机 EXE 程序


二、运行效果说明

整体更新流程如下:

  1. 点击「获取最新版本」
  2. 请求远程version.txt
  3. 发现新版本 → 弹窗提示
  4. 用户确认 → 下载update.zip
  5. 显示下载进度条
  6. 解压更新文件
  7. 备份旧 EXE
  8. 替换新 EXE
  9. 提示升级完成并退出程序

三、环境与依赖说明

1️⃣ Python 版本

Python 3.8+

2️⃣ pip 依赖安装

pipinstallPyQt5 pipinstallrequests pipinstallpackaging

(如需打包 EXE)

pipinstallpyinstaller

四、服务器端准备

1️⃣ 版本号文件(version.txt)

1.2.0

2️⃣ 更新包(update.zip)

update.zip ├── update.exe ├── logo.png(可选)

五、完整代码

SoftVesion.pydefcurrent_version():""" Returns the version of the package """return"1.1.0"deflatest_version():""" Returns the latest version of the package """return"1.1.0"defupgrade_date():""" Returns the time of the upgrade """return"2024年1月19日"defcurrent_title():""" Returns the title of the package """return"Excel常用小工具"defremote_version_url():""" Returns the url of the latest version """return"http://82.157.62.197:97/version.txt"defupdate_url():""" Returns the url of the version info """return"http://192.168.31.219:8080/update.zip"

UpdateApp.py

importosimportzipfileimportrequestsfrompackagingimportversionfromPyQt5.QtCoreimportQThread,pyqtSignal,QtfromPyQt5.QtWidgetsimportQApplication,QDialog,QVBoxLayout,QMainWindow,QPushButton,QMessageBox,QProgressDialog,QLabel,QAction,QDesktopWidgetimportshutilfrom.SoftVesionimportcurrent_version,latest_version,remote_version_url,update_url,current_titlefromPyQt5.QtGuiimportQStandardItemModel,QStandardItem,QIconimportsysimporttimeimportsubprocessclassDownloadThread(QThread):progressChanged=pyqtSignal(int)downloadFinished=pyqtSignal()unableToFetchUpdateLink=pyqtSignal()def__init__(self,url,save_path):super().__init__()self.url=url self.save_path=save_pathdefrun(self):try:response=requests.get(self.url,stream=True)ifresponse.status_code==200:total_size=int(response.headers.get('content-length',0))downloaded_size=0withopen(self.save_path,'wb')asfile:fordatainresponse.iter_content(chunk_size=8192):file.write(data)downloaded_size+=len(data)progress=int((downloaded_size/total_size)*100)self.progressChanged.emit(progress)self.downloadFinished.emit()else:print("Error fetching update link:")self.unableToFetchUpdateLink.emit()exceptExceptionase:print("Error fetching update link:",e)self.unableToFetchUpdateLink.emit()classUpdateApp(QDialog):def__init__(self,parent=None):super().__init__(parent)self.current_version=current_version()# 当前应用程序版本号self.latest_version=latest_version()self.progress_dialog=Noneself.download_thread=Noneself.remote_version_url=remote_version_url()self.update_url=update_url()self.init_ui()#self.show_update_notification()defmove_to_center(self,widget):# 将 widget 移动到屏幕中央desktop_center=QDesktopWidget().availableGeometry().center()widget_frame=widget.frameGeometry()widget_frame.moveCenter(desktop_center)widget.move(widget_frame.topLeft())definit_ui(self):self.setFixedSize(300,200)self.setWindowTitle("检查更新")icon=QIcon("icon.png")self.setWindowIcon(icon)self.version_label=QLabel("当前版本号: "+self.current_version,self)self.version_label.setAlignment(Qt.AlignCenter)self.version_label.setGeometry(100,10,110,20)self.update_button=QPushButton("获取最新版本",self)self.update_button.setGeometry(100,60,110,40)self.update_button.clicked.connect(self.show_update_notification)ifself.download_thread:self.download_thread.unableToFetchUpdateLink.connect(self.show_unable_to_fetch_update_link)defshow_unable_to_fetch_update_link(self):QMessageBox.critical(self,"无法获取更新链接","无法获取更新链接,请检查网络连接。")defupdate_app(self):try:remote_version=self.get_remote_version()ifversion.parse(remote_version)>version.parse(self.current_version):ifself.has_network_connection():self.perform_upgrade()else:QMessageBox.information(self,"无法获取版本号","无法获取远程版本号,请检查网络连接。")else:QMessageBox.information(self,"无需升级","当前应用程序已经是最新版本。")except:QMessageBox.information(self,"无法获取版本号","无法获取远程版本号,请检查网络连接。")defget_remote_version(self):try:response=requests.get(self.remote_version_url)ifresponse.status_code==200:returnresponse.text.strip()returnself.latest_versionexcept:returnself.latest_versiondefperform_upgrade(self):update_url=self.update_url temp_zip_path="temp_update.zip"self.download_thread=DownloadThread(update_url,temp_zip_path)self.download_thread.progressChanged.connect(self.update_progress_bar)self.download_thread.downloadFinished.connect(self.handle_download_finished)self.progress_dialog=QProgressDialog("正在下载更新...",None,0,100,self)self.progress_dialog.setWindowModality(Qt.WindowModal)self.progress_dialog.setAutoClose(False)self.progress_dialog.setAutoReset(False)self.progress_dialog.setWindowTitle("下载进度")self.move_to_center(self.progress_dialog)self.progress_dialog.canceled.connect(self.download_thread.quit)self.download_thread.start()defupdate_progress_bar(self,progress):self.progress_dialog.setValue(progress)defhandle_download_finished(self):self.progress_dialog.hide()ifos.path.exists("temp_update.zip"):self.process_download("temp_update.zip")os.remove("temp_update.zip")sys.exit()defhas_network_connection(self):try:requests.get(remote_version_url(),timeout=5)returnTrueexcept:returnFalsedefshow_update_notification(self):try:remote_version=self.get_remote_version()ifversion.parse(remote_version)>version.parse(self.current_version):reply=QMessageBox.question(self,"版本更新提示",f"有新版本可用:{remote_version}\n您当前的版本:{self.current_version}\n是否要更新?",QMessageBox.Yes|QMessageBox.No)ifreply==QMessageBox.Yes:self.update_app()else:QMessageBox.information(self,"版本更新提示","您当前的版本是最新版本。")except:passif__name__=="__main__":app=QApplication([])window=UpdateApp()window.show()app.exec_()

六、关键设计说明

✔ 使用 QThread 防止界面卡死

✔ 使用 packaging.version 进行版本比较

✔ ZIP 更新包支持扩展文件

✔ EXE 覆盖前自动备份

✔ 更新完成后安全退出


七、适用场景

  • PyQt5 工具软件
  • 内部办公系统
  • 单机 EXE 程序
  • 不依赖第三方更新框架

八、总结

本文提供的是一个可直接落地、真实可用的 PyQt5 自动更新方案,
无需复杂服务器逻辑,维护成本极低。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/7 3:32:40

C#集合筛选实战精要(高手都在用的5种写法)

第一章:C#集合筛选的核心概念与应用场景在C#开发中,集合筛选是处理数据的核心操作之一。通过LINQ(Language Integrated Query),开发者可以以声明式语法高效地从数组、列表、字典等集合中提取符合条件的元素&#xff0c…

作者头像 李华
网站建设 2026/9/7 1:41:52

基于SpringBoot+Vue的在线装修管理系统管理系统设计与实现【Java+MySQL+MyBatis完整源码】

摘要 随着互联网技术的快速发展和人们生活水平的不断提高,装修行业逐渐向数字化、智能化方向转型。传统的装修管理模式依赖人工操作,存在信息传递效率低、管理成本高、服务质量难以保障等问题。在线装修管理系统通过整合装修流程中的设计、施工、材料采购…

作者头像 李华
网站建设 2026/9/7 7:25:40

用 Web 开发思维理解 Agent 的三大支柱——Tools + Memory + LLM

图片来源网络,侵权联系删。 文章目录1. 引言2. 核心概念解析:Tools、Memory、LLM 如何协同工作?2.1 三大组件类比 Web 开发2.2 协同工作流程(Mermaid)3. 实战项目:构建“智能旅行规划助手”3.1 功能需求3.2…

作者头像 李华
网站建设 2026/9/2 0:59:25

医疗健康领域探索:HeyGem生成医生形象科普短片

医疗健康领域的AI数字人实践:用HeyGem批量生成医生形象科普视频 在三甲医院的宣教科办公室里,一场关于“高血压防治”的短视频制作会议正在进行。按照传统流程,他们需要协调心内科专家排期、安排拍摄场地、准备灯光设备、录制讲解内容&#x…

作者头像 李华
网站建设 2026/9/2 1:00:18

科哥开发的HeyGem系统安全性如何?本地部署无数据泄露风险

HeyGem系统安全性如何?本地部署无数据泄露风险 在AI生成内容(AIGC)迅速普及的今天,越来越多企业开始尝试用“数字人”制作宣传视频、教学课件或客服播报。但一个现实问题随之而来:这些音视频往往包含敏感信息——比如银…

作者头像 李华
网站建设 2026/9/2 0:59:13

工业自动化中eSPI协议的优势与挑战:通俗解释

eSPI为何正在重塑工业自动化通信?一文讲透它的实战价值在一间现代化的智能制造车间里,PLC控制器正通过千兆以太网与上位机交换数据,机器人臂按节拍精准作业。但你可能没注意到,在这些设备主板的最底层,一场“静默的技术…

作者头像 李华