PyQt5实现远程更新exe可执行文件

news2025/2/28 21:28:01

PyQt5实现远程下载更新exe可执行文件

1、实现流程

1、获取远程http地址
2、获取需要更新的exe文件
3、点击更新
4、把exe强关闭
5、下载文件
6、更新

2、效果图

在这里插入图片描述

3、示例代码

conf.ini配置文件:

{"http_address_edit_value": "http://xxx.com/xxx/xxx.exe", "exe_name_edit_value": "\u83b7\u53d6IP.exe", "version_num_edit_value": "4.5.16"}

main.py文件:

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

"""
@contact: 微信 1257309054
@file: main.py
@time: 2024/3/9 21:16
@author: LDC
"""

import datetime
import json
import logging
import os
import subprocess
import sys
import time

import psutil as psutil
import requests
from PyQt5.QtCore import QThread, pyqtSignal
from PyQt5.QtWidgets import QMainWindow, QApplication

from update import Ui_MainWindow


class Window(QMainWindow, Ui_MainWindow):
    def __init__(self):
        super(QMainWindow, self).__init__()
        self.log_msg = None  # 更新日志
        self.setup_ui()  # 渲染画布
        self.update_thread = UpdateThread(self)  # 开启线程循环监控是否可以下载
        self.connect_signals()  # 绑定触发事件

    def setup_ui(self):
        self.setupUi(self)  # 渲染pyqt5界面
        self.get_conf_ini()  # 获取当前参数
        self.http_address_edit_value = self.conf['http_address_edit_value']  # 远程更新exe文件地址
        self.http_address_edit.setText(self.http_address_edit_value)
        self.exe_name_edit_value = self.conf['exe_name_edit_value']  # exe文件名
        self.exe_name_edit.setText(self.exe_name_edit_value)
        self.version_num_edit_value = self.conf['version_num_edit_value']  # 版本号
        self.version_num_edit.setText(self.version_num_edit_value)
        self.log_edit.setText('{},{}当前版本号{}'.format(
            datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S'),
            self.exe_name_edit_value,
            self.version_num_edit_value),

        )

    def get_conf_ini(self):
        # 读取conf.ini
        self.conf = {}
        with open(r'conf.ini', 'r', encoding='utf-8') as f:
            self.conf = json.loads(f.read())

    def connect_signals(self):
        # 绑定触发事件
        self.btn_save.clicked.connect(self.btn_save_clicked)
        self.btn_update.clicked.connect(self.btn_update_clicked)
        # 输入框输入完成事件
        self.http_address_edit.editingFinished.connect(self.http_address_edit_changed)
        self.exe_name_edit.editingFinished.connect(self.exe_name_edit_changed)
        self.version_num_edit.editingFinished.connect(self.version_num_edit_changed)
        self.update_thread._signal_update.connect(self.update_threading_slot)

    def http_address_edit_changed(self):
        # 修改远程地址
        self.http_address_edit_value = self.http_address_edit.text()
        self.conf['http_address_edit_value'] = self.http_address_edit_value

    def exe_name_edit_changed(self):
        # 修改exe文件名
        self.exe_name_edit_value = self.exe_name_edit.text()
        self.conf['exe_name_edit_value'] = self.exe_name_edit_value

    def version_num_edit_changed(self):
        # 修改版本号
        self.version_num_edit_value = self.version_num_edit.text()
        self.conf['version_num_edit_value'] = self.version_num_edit_value

    def btn_update_clicked(self):
        # 更新exe文件
        msg = '准备更新软件,正在关闭{}'.format(self.exe_name_edit_value)
        print(msg)
        self.log_edit.append(msg)
        self.btn_update.setText('更新中...')
        self.update_thread.start()  # 开始下载

    def btn_save_clicked(self):
        # 保存
        with open(r'conf.ini', 'w', encoding='utf-8') as f:
            f.write(json.dumps(self.conf))

    def save_log(self):
        # 保存
        if not self.log_msg:
            return
        with open(r'update_log.txt', 'a', encoding='utf-8') as f:
            f.write(self.log_msg)
            f.write('\n')

    def update_threading_slot(self, data):
        # 线程回调函数
        data = json.loads(data)
        is_update = data['is_update']
        if is_update == 1:
            msg = '{},更新成功,版本号:{}'.format(datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S'),
                                          self.version_num_edit_value)
            self.log_msg = msg
            self.save_log()
            self.log_edit.append(msg)
            self.btn_update.setText('更新')
            print('更新成功')
        elif is_update == 2:
            self.log_edit.append('{},开始更新'.format(datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S')))
            print('开始更新')
        else:
            self.log_edit.append('{},更新失败,找不到远程文件'.format(datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S')))
            self.btn_update.setText('更新')
            print('更新失败')


class UpdateThread(QThread):
    # 监控线程
    _signal_update = pyqtSignal(str)

    def __init__(self, parent=None):
        super(UpdateThread, self).__init__(parent)
        self.window = parent

    def run(self):
        '''
        监控程序
        '''
        while 1:
            time.sleep(1)
            try:

                while self.is_process_running(self.window.exe_name_edit_value):
                    os.popen('taskkill /f /im {}'.format(self.window.exe_name_edit_value))  # 关闭程序
                    time.sleep(2)
                self._signal_update.emit(json.dumps({'is_update': 2}))  # 发送信号给槽函数
                # 下载远程exe文件
                r = requests.get(self.window.http_address_edit_value)
                with open(self.window.exe_name_edit_value, 'wb') as code:
                    code.write(r.content)
                self._signal_update.emit(json.dumps({'is_update': 1}))  # 发送信号给槽函数

            except:
                self._signal_update.emit(json.dumps({'is_update': 0}))  # 发送信号给槽函数

            break

    def is_process_running(self, process_name):
        # 查看程序是否还存活
        for process in psutil.process_iter():
            try:
                if process.name() == process_name:
                    return True
            except (psutil.NoSuchProcess, psutil.AccessDenied, psutil.ZombieProcess):
                pass
        return False


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

ui.py文件:

# -*- coding: utf-8 -*-
"""
@contact: 微信 1257309054
@file: main.py
@time: 2024/3/9 21:16
@author: LDC
"""
# Form implementation generated from reading ui file 'update.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(714, 431)
        self.centralwidget = QtWidgets.QWidget(MainWindow)
        self.centralwidget.setObjectName("centralwidget")
        self.textBrowser = QtWidgets.QTextBrowser(self.centralwidget)
        self.textBrowser.setGeometry(QtCore.QRect(15, 10, 681, 51))
        self.textBrowser.setObjectName("textBrowser")
        self.label = QtWidgets.QLabel(self.centralwidget)
        self.label.setGeometry(QtCore.QRect(20, 80, 54, 31))
        self.label.setObjectName("label")
        self.http_address_edit = QtWidgets.QLineEdit(self.centralwidget)
        self.http_address_edit.setGeometry(QtCore.QRect(80, 79, 501, 31))
        self.http_address_edit.setObjectName("http_address_edit")
        self.btn_save = QtWidgets.QPushButton(self.centralwidget)
        self.btn_save.setGeometry(QtCore.QRect(590, 80, 75, 31))
        self.btn_save.setObjectName("btn_save")
        self.label_2 = QtWidgets.QLabel(self.centralwidget)
        self.label_2.setGeometry(QtCore.QRect(20, 120, 54, 31))
        self.label_2.setObjectName("label_2")
        self.exe_name_edit = QtWidgets.QLineEdit(self.centralwidget)
        self.exe_name_edit.setGeometry(QtCore.QRect(80, 120, 271, 31))
        self.exe_name_edit.setObjectName("exe_name_edit")
        self.btn_update = QtWidgets.QPushButton(self.centralwidget)
        self.btn_update.setGeometry(QtCore.QRect(590, 120, 75, 31))
        self.btn_update.setObjectName("btn_update")
        self.label_3 = QtWidgets.QLabel(self.centralwidget)
        self.label_3.setGeometry(QtCore.QRect(20, 160, 54, 31))
        self.label_3.setObjectName("label_3")
        self.label_4 = QtWidgets.QLabel(self.centralwidget)
        self.label_4.setGeometry(QtCore.QRect(360, 130, 41, 21))
        self.label_4.setObjectName("label_4")
        self.version_num_edit = QtWidgets.QLineEdit(self.centralwidget)
        self.version_num_edit.setGeometry(QtCore.QRect(400, 119, 181, 31))
        self.version_num_edit.setObjectName("version_num_edit")
        self.log_edit = QtWidgets.QTextBrowser(self.centralwidget)
        self.log_edit.setGeometry(QtCore.QRect(80, 170, 501, 192))
        self.log_edit.setObjectName("log_edit")
        MainWindow.setCentralWidget(self.centralwidget)
        self.menubar = QtWidgets.QMenuBar(MainWindow)
        self.menubar.setGeometry(QtCore.QRect(0, 0, 714, 23))
        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.textBrowser.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:26pt; color:#0000ff;\">远程更新exe可执行文件</span></p></body></html>"))
        self.label.setText(_translate("MainWindow", "远程地址"))
        self.btn_save.setText(_translate("MainWindow", "保存"))
        self.label_2.setText(_translate("MainWindow", "exe文件名"))
        self.btn_update.setText(_translate("MainWindow", "更新"))
        self.label_3.setText(_translate("MainWindow", "更新日志"))
        self.label_4.setText(_translate("MainWindow", "版本号"))

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

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

相关文章

【敬伟ps教程】文字处理工具

文章目录 文字工具使用方式文字图层文字工具选项字符面板段落面板文字工具使用方式 文字工具(快捷键T),包含横排和直排两种类型 创建文本两种类型:点式文本、段落文本 创建文字方式 1、在画面上单击,出现文字光标,可输入文字,然后需要在工具栏中点击“√”或者 Ctrl+…

【二十九】springboot高并发示例

本章演示在springboot项目中的高并发demo&#xff0c;演示导致的问题&#xff0c;以及单机部署下的解决方案和集群部署下的解决方式以及分布式下的解决方案。 目录 一、单机模式下高并发问题 二、集群模式下高并发问题 一、单机模式下高并发问题 前提&#xff1a;先写一个减扣…

枚举赋值及强制转换问题

对枚举进行字符赋值&#xff0c;需要进行强制类型转换之后&#xff0c;才能得到想要的值&#xff0c;如下 typedef enum data {DIRECTION_X X,DIRECTION_Y Y,DIRECTION_Z Z,DIRECTION_T T }NumData;int main() {NumData numdata DIRECTION_Y;count <<"num is&…

Qt开发QHostInfo主机地址查询组件

Qt 是一个跨平台C图形界面开发库&#xff0c;利用Qt可以快速开发跨平台窗体应用程序&#xff0c;在Qt中我们可以通过拖拽的方式将不同组件放到指定的位置&#xff0c;实现图形化开发极大的方便了开发效率&#xff0c;本章将重点介绍如何运用QHostInfo组件实现对主机地址查询功能…

数据库-第十一章 并发控制【期末复习|考研复习】

前言 总结整理不易&#xff0c;希望大家点赞收藏。 给大家整理了一下数据库系统概论中的重点概念&#xff0c;以供大家期末复习和考研复习的时候使用。 参考资料是王珊老师和萨师煊老师的数据库系统概论(第五版)。 数据库系统概论系列文章传送门&#xff1a; 第一章 绪论 第二/…

机器学习第29周周报 Beyond Dropout

文章目录 week29 Beyond Dropout摘要Abstract一、泛化理论二、文献阅读1. 题目2. abstract3. 网络架构3.1 特征图失真3.2 失真优化 4. 文献解读4.1 Introduction4.2 创新点4.3 实验过程4.3.1 全连接层实验4.3.2 卷积网络上的实验 4.4 结论 小结参考文献 week29 Beyond Dropout …

visualization_msgs::Marker 的pose设置,map坐标系的3d box显示问题

3D框显示 3D框显示可以使用visualization_msgs::Marker::LINE_LIST或者LINE_STRIP&#xff0c;前者使用方法需要指明线的两个端点&#xff0c;后者自动连接相邻两个点。 姿态问题 网上看了一些&#xff0c;没有涉及到朝向设置&#xff0c;Pose.orientation默认构造为4个0 至…

Spring官网中查看MongoDB的API文档的详细步骤

目录 Spring官网中查看MongoDB的API文档的详细步骤1、进入 Spring 官网2、选择 Mongodb的文档介绍3、点击API文档4、进入文档查询页面 Spring官网中查看MongoDB的API文档的详细步骤 1、进入 Spring 官网 首先进入Spring的官网&#xff0c;然后点击【Spring Data】 2、选择 Mon…

JAVA实战开源项目:大学兼职教师管理系统(Vue+SpringBoot)

目录 一、摘要1.1 项目介绍1.2 项目录屏 二、研究内容三、界面展示3.1 登录注册3.2 学生教师管理3.3 课程管理模块3.4 授课管理模块3.5 课程考勤模块3.6 课程评价模块3.7 课程成绩模块3.8 可视化图表 四、免责说明 一、摘要 1.1 项目介绍 大学兼职教师管理系统&#xff0c;旨…

王阳明:在心里中一个春天!吃好喝好不等于吃饱喝足,出租屋的第二个周末——早读(逆天打工人爬取热门微信文章解读)

种一个春天&#xff0c;等下一个天亮 引言Python 代码第一篇 霸王别坤第二篇 &#xff08;跳&#xff09;洞见 王阳明&#xff1a;人生若是太苦寒&#xff0c;在心里种一个春天第三篇 人民日报 来了&#xff01;新闻早班车要闻社会政策 结尾 屋宽不如心宽&#xff0c;物整亦是心…

模拟框图的表示

微分方程的建立 目的&#xff1a;为建立LTI系统的数学模型&#xff0c;需要列写微分方程式。 以RLC电路为例&#xff1a; 以Us为输入&#xff0c;Uc为输入&#xff0c;则可以得出以下微分方程式&#xff1a; 抽去物理意义后&#xff0c;得到一般的常微分线性方程&#xff1a;…

YOLOv5-Openvino-ByteTrack【CPU】

纯检测如下&#xff1a; YOLOv5-Openvino和ONNXRuntime推理【CPU】 YOLOv6-Openvino和ONNXRuntime推理【CPU】 YOLOv8-Openvino和ONNXRuntime推理【CPU】 YOLOv9-Openvino和ONNXRuntime推理【CPU】 注&#xff1a;YOLOv5和YOLOv6代码内容基本一致&#xff01; 全部代码Github&…

思维调试:为什么FormatMessage提示找不到资源?

在不调试的情况下解决下面的问题&#xff0c;说明你的思维调试能力又进阶了。 问题 我在调用 FormatMessage 函数加载一个插入的资源字符串&#xff0c;由于某种未知的原因&#xff0c;它没能按预期那样工作。 我要加载的字符串类似于这样的 “Blah blah blah %1. Blah blah …

VIM编译器的安装

文章目录 前言一、VIM软件安装二、遇到问题三、VIM使用1.文档创建命令touch2.VIM编译器输入模式3.VIM编译器指令模式3.VIM编译器底行模式4.VIM编译器使用小技巧 前言 &#x1f4a6; 我们如果要在终端模式下进行文本编辑或者修改文件就可以使用 VIM 编辑器&#xff0c;VIM 编辑…

腾讯云轻量应用服务器流量用完了怎么办?

腾讯云轻量服务器流量用完了怎么办&#xff1f;超额流量另外支付流量费&#xff0c;流量价格为0.8元/GB&#xff0c;会自动扣你的腾讯云余额&#xff0c;如果你的腾讯云账号余额不足&#xff0c;那么你的轻量应用服务器会面临停机&#xff0c;停机后外网无法访问&#xff0c;继…

如何修复advapi32.dll丢失无法启动程序的问题

如果你在运行Windows程序时遇到了“advapi32.dll丢失无法启动程序”的错误消息&#xff0c;那么这意味着你的计算机缺少这个DLL文件。在本文中&#xff0c;我们将提供一些解决方案&#xff0c;帮助你解决这个问题并恢复计算机的正常运行。 一.advapi32.dll丢失电脑的提示 关于…

BUUCTF----[极客大挑战 2019]HardSQL

输入1’ 单引号闭合 进行永真式判断 竟然说我是臭弟弟----八嘎&#xff08;肯定是进行了过滤&#xff09; 经过手法判断&#xff0c;过滤了&#xff0c;空格&#xff0c;and等报错注入updatexml() 报错注入顾名思义就是&#xff0c;通过特殊函数错误使用并使其输出错误结果来获…

RLAIF(0)—— DPO(Direct Preference Optimization) 原理与代码解读

之前的系列文章&#xff1a;介绍了 RLHF 里用到 Reward Model、PPO 算法。 但是这种传统的 RLHF 算法存在以下问题&#xff1a;流程复杂&#xff0c;需要多个中间模型对超参数很敏感&#xff0c;导致模型训练的结果不稳定。 斯坦福大学提出了 DPO 算法&#xff0c;尝试解决上面…

VMware下载与安装

准备一个Linux的系统&#xff0c;成本最低的方式就是在本地安装一台虚拟机&#xff0c;VMware是业界最好用的虚拟机软件之一 官网&#xff1a;https://www.vmware.com/ 下载页面&#xff1a;https://www.vmware.com/products/workstation-pro/workstation-pro-evaluation.html …

Python 3 教程(3)

958 在 Windows 下可以不写第一行注释: #!/usr/bin/python3 第一行注释标的是指向 python 的路径&#xff0c;告诉操作系统执行这个脚本的时候&#xff0c;调用 /usr/bin 下的 python 解释器。 此外还有以下形式&#xff08;推荐写法&#xff09;&#xff1a; #!/usr/bin/env p…