news 2026/4/23 13:55:05

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/4/18 9:22:11

VS Code调试.NET Core应用,90%开发者忽略的3个关键配置项

第一章:C# 跨平台调试配置概述在现代软件开发中,C# 不再局限于 Windows 平台,借助 .NET SDK 和 Visual Studio Code 等工具,开发者可以在 Linux、macOS 和 Windows 上实现一致的跨平台调试体验。合理配置调试环境是确保应用在不同…

作者头像 李华
网站建设 2026/4/11 9:59:17

【C#高性能编程实战】:揭秘交错数组索引访问的底层机制

第一章:C#交错数组索引访问的核心概念C#中的交错数组(Jagged Array)是一种特殊的多维数组结构,它由数组的数组构成,每一行可以拥有不同长度的子数组。这种灵活性使其在处理不规则数据结构时尤为高效。与矩形数组不同&a…

作者头像 李华
网站建设 2026/4/13 3:51:07

Ettercap 的高效使用

Ettercap 的高效使用核心在于明确攻击场景 选对模式 / 插件 提前解决配置问题(比如你刚才遇到的 SSL 解析、IPv6 临时地址问题)。作为白帽子,我们主要用它做中间人攻击(MITM)、流量嗅探、密码捕获、ARP 欺骗等合法渗…

作者头像 李华
网站建设 2026/4/18 16:28:00

【2025最新】基于SpringBoot+Vue的员工健康管理系统管理系统源码+MyBatis+MySQL

摘要 随着企业规模的不断扩大和员工健康意识的提升,传统的纸质健康管理方式已无法满足现代企业的需求。员工健康管理系统的数字化和智能化成为企业管理的必然趋势。该系统旨在通过信息化手段,实现对员工健康数据的全面采集、分析和预警,帮助企…

作者头像 李华
网站建设 2026/4/16 23:54:03

全面讲解Arduino创意作品与TDS水质传感器协同工作

手把手教你用Arduino玩转TDS水质检测:从原理到实战,打造智能水卫士你有没有想过,一杯看似清澈的水,里面到底“藏”了多少看不见的溶解物质?在家庭饮水、鱼缸养护、无土栽培甚至环保监测中,水质安全早已不再…

作者头像 李华
网站建设 2026/4/19 15:04:24

HeyGem配合Notion数据库管理生成任务?高效协作新模式

HeyGem 与 Notion 联动:构建数字人视频生成的高效协作流 在内容创作日益依赖 AI 的今天,一个现实问题摆在许多团队面前:即便拥有了强大的本地化数字人生成系统,如何让多人协作不混乱、任务进度可追踪、资源复用更便捷?…

作者头像 李华