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

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", "版本号"))

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

python统计日志中数据从开始到结束的响应时间的最大值、最小值、平均值、中位数

应用场景&#xff1a;需要根据日志文件&#xff0c;统计出数据从开始下发到收到回复所需的时间&#xff0c;包括最大值、最小值、平均值、中位数。 日志格式如图类似&#xff0c;每一行日志开始部分就是所需要截取的时间&#xff1b;1条日记是以某些关键词作为开始&#xff0c;…

SSD的原理

简介 SSD&#xff08;Solid State Drive&#xff09;是一种使用闪存存储芯片&#xff08;NAND Flash&#xff09;的存储设备。与传统的机械硬盘不同&#xff0c;SSD没有移动部件&#xff0c;因此具有更快的读写速度和更低的能耗。 架构 NAND Flash是一种非易失性存储器&…

javase day01笔记

第一天课堂笔记 Java第三代高级语言中的面向对象的语言 b/s 浏览器/服务器c/s 客户端/服务端 1991年詹姆斯高斯林在sun公司开发的Java 常用的dos命令 磁盘操作系统&#xff1a;dos win &#xff0b; r -》 cmd dos命令 切换盘符&#xff1a;直接输入对应盘符目录操作&#x…

6个维度分析实时渲染和Webgl技术异同

在日常交流中&#xff0c;对Webgl技术熟悉的合作伙伴&#xff0c;在初次了解实时渲染技术时&#xff0c;都会问二者之间的异同。目前很多要求B/S架构的项目&#xff0c;很多在用webgl技术路线&#xff0c;而且这个方案在行业里比较普&#xff0c;业主方对这个也比较熟悉&#x…

基于git推送的ES检索pdf内容优化思路与代码实现

写在前面 在之前的内容中我们已经介绍了创建gitbucket的webHook&#xff0c;使得仓库有更新时自动推送到我们定义的接口&#xff1b;然后Java读取仓库的文件转码写入ES库&#xff0c;这些核心流程已经实现。 1. 实现ES检索pdf等文件内容的插件 2. 基于GitBucket的Hook构建ES…

8. 超级终端和 Minicom

超级终端和 Minicom 在对目标板进行查看、操作或目标板和上位机进行文件传输与通信时&#xff0c;需要安装终端软件。通过终端软件来对目标板进行配置&#xff0c;或者执行目标板上的程序与主机进行通信。 下面介绍 3种终端软件&#xff0c;具体开发时&#xff0c;你仅需任意使…

乐优商城(九)数据同步

1. 项目问题分析 现在项目中有三个独立的微服务&#xff1a; 商品微服务&#xff1a;原始数据保存在 MySQL 中&#xff0c;从 MySQL 中增删改查商品数据。搜索微服务&#xff1a;原始数据保存在 ES 的索引库中&#xff0c;从 ES 中查询商品数据。商品详情微服务&#xff1a;做…

2024 年 AI 辅助研发发展与趋势研究

引言 这几年&#xff0c;人工智能&#xff08;AI&#xff09;技术火得不行&#xff0c;它渗透到了我们生活的方方面面。从帮助我们识别图片、理解语音&#xff0c;到推荐我们喜欢的内容&#xff0c;甚至自动驾驶汽车&#xff0c;AI都在大显身手。特别是在研发领域&#xff0c;…

代码随想录训练营第41天 | 动态规划:01背包理论基础、动态规划:01背包理论基础(滚动数组)、LeetCode 416.分割等和子集

动态规划&#xff1a;01背包理论基础 文章讲解&#xff1a;代码随想录(programmercarl.com) 视频讲解&#xff1a;带你学透0-1背包问题&#xff01;_哔哩哔哩_bilibili 动态规划&#xff1a;01背包理论基础&#xff08;滚动数组&#xff09; 文章讲解&#xff1a;代码随想录(…

好好好,这样玩是吧。

python聊天机器人 //1.安装方法 pip install requests //2.实例 import requestsdef chat_bot():url http://api.qingyunke.com/api.phpparams {key: free,appid: 0}print("你好&#xff01;开始对话吧&#xff08;输入exit退出&#xff09;")while True:user_in…

Navicat Premium:掌控数据库的强大工具

在当今数字化的时代&#xff0c;数据管理变得越来越重要。无论您是数据库管理员、开发人员还是普通用户&#xff0c;找到一个高效、易用的数据库管理工具是至关重要的。Navicat Premium for Mac/Win 就是这样一款强大的多协议数据库管理工具&#xff0c;它将为您的数据库管理体…

指纹加密U盘/指纹KEY方案——采用金融级安全芯片 ACH512

方案概述 指纹加密U盘解决方案可实现指纹算法处理、数据安全加密、数据高速存取&#xff08;EMMC/TF卡/NandFlash&#xff09;&#xff0c;可有效保护用户数据安全。 方案特点 • 采用金融级安全芯片 ACH512 • 存储介质&#xff1a;EMMC、TF卡、NandFlash • 支持全系列国密…

docker 使用官方镜像搭建 PHP 环境

一、所需环境&#xff1a; 1、PHP&#xff1a;7.4.33-fpm 的版本 2、Nginx&#xff1a;1.25.1 的版本 3、MySQL&#xff1a; 5.7 的版本 4、Redis&#xff1a;7.0 的版本 1.1、拉取官方的镜像 docker pull php:7.4.33-fpm docker pull nginx:1.25.1 docker pull mysql:5.7 do…

Java编程实战:构建校园二手物品交易系统

✍✍计算机编程指导师 ⭐⭐个人介绍&#xff1a;自己非常喜欢研究技术问题&#xff01;专业做Java、Python、微信小程序、安卓、大数据、爬虫、Golang、大屏等实战项目。 ⛽⛽实战项目&#xff1a;有源码或者技术上的问题欢迎在评论区一起讨论交流&#xff01; ⚡⚡ Java实战 |…

Toyota Programming Contest 2024#3(AtCoder Beginner Contest 344)(A~C)

A - Spoiler 竖线里面的不要输出&#xff0c;竖线只有一对&#xff0c;且出现一次。 #include <bits/stdc.h> //#define int long long #define per(i,j,k) for(int (i)(j);(i)<(k);(i)) #define rep(i,j,k) for(int (i)(j);(i)>(k);--(i)) #define debug(a) cou…

Qt教程3-Ubuntu(x86_64)上配置arm64(aarch64)交叉编译环境及QT编译arm64架构工程

汇创慧玩 写在前面1. 查看系统架构相关指令2. ARM64交叉编译器环境搭建3. Qt编译arm64环境搭建4. 配置 Qt的本地aarch64交叉编译器5. 工程建立及编译验证 写在前面 苦辣酸甜时光八载&#xff0c;春夏秋冬志此一生 Qt简介&#xff1a; Qt&#xff08;官方发音 [kju:t]&#xff…

配置oh-my-posh

在windows上的powershell上配置oh-my-posh&#xff0c;使其更像在linux用oh-my-zsh。 首先打开powershell&#xff0c;输入&#xff1a; winget install JanDeDobbeleer.OhMyPosh -s winget安装on-my-posh.exe和oh-my-posh上最新的主题。 之后重启powershell。 打开配置文件…

flink重温笔记(十三): flink 高级特性和新特性(2)——ProcessFunction API 和 双流 join

Flink学习笔记 前言&#xff1a;今天是学习 flink 的第 13 天啦&#xff01;学习了 flink 高级特性和新特性之ProcessFunction API 和 双流 join&#xff0c;主要是解决大数据领域数据从数据增量聚合的问题&#xff0c;以及快速变化中的流数据拉宽问题&#xff0c;即变化中多个…

【简写Mybatis】03-Mapper xml的注册和使用

前言 在学习MyBatis源码文章中&#xff0c;斗胆想将其讲明白&#xff1b;故有此文章&#xff0c;如有问题&#xff0c;不吝指教&#xff01; 注意&#xff1a; 学习源码一定一定不要太关注代码的编写&#xff0c;而是注意代码实现思想&#xff1b; 通过设问方式来体现代码中的…

vSphere 8考试认证题库 2024最新(VCP 8.0版本)

VMware VCP-DCV&#xff08;2V0-21.23&#xff09;认证考试题库&#xff0c;已全部更新&#xff0c;答案已经完成校对&#xff0c;完整题库请扫描上方二维码访问。正常考可以考到450分以上&#xff08;满分500分&#xff0c;300分通过&#xff09; An administrator is tasked …