基于Pyside6开发一个通用的在线升级工具

UI

main.ui

<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0"><class>MainWindow</class><widget class="QMainWindow" name="MainWindow"><property name="geometry"><rect><x>0</x><y>0</y><width>562</width><height>96</height></rect></property><property name="font"><font><family>微软雅黑</family><pointsize>10</pointsize></font></property><property name="windowTitle"><string>在线升级</string></property><widget class="QWidget" name="centralwidget"><widget class="QProgressBar" name="pbDownload"><property name="geometry"><rect><x>10</x><y>60</y><width>541</width><height>31</height></rect></property><property name="value"><number>0</number></property><property name="alignment"><set>Qt::AlignCenter</set></property><property name="textVisible"><bool>false</bool></property></widget><widget class="QLabel" name="label"><property name="geometry"><rect><x>10</x><y>10</y><width>541</width><height>41</height></rect></property><property name="font"><font><family>微软雅黑</family><pointsize>10</pointsize></font></property><property name="text"><string>在线升级中,请稍等...</string></property><property name="alignment"><set>Qt::AlignCenter</set></property></widget></widget></widget><resources/><connections/>
</ui>

main.py

# -*- coding: utf-8 -*-################################################################################
## Form generated from reading UI file 'main.ui'
##
## Created by: Qt User Interface Compiler version 6.6.3
##
## WARNING! All changes made in this file will be lost when recompiling UI file!
################################################################################from PySide6.QtCore import (QCoreApplication, QDate, QDateTime, QLocale,QMetaObject, QObject, QPoint, QRect,QSize, QTime, QUrl, Qt)
from PySide6.QtGui import (QBrush, QColor, QConicalGradient, QCursor,QFont, QFontDatabase, QGradient, QIcon,QImage, QKeySequence, QLinearGradient, QPainter,QPalette, QPixmap, QRadialGradient, QTransform)
from PySide6.QtWidgets import (QApplication, QLabel, QMainWindow, QProgressBar,QSizePolicy, QWidget)class Ui_MainWindow(object):def setupUi(self, MainWindow):if not MainWindow.objectName():MainWindow.setObjectName(u"MainWindow")MainWindow.resize(562, 96)font = QFont()font.setFamilies([u"\u5fae\u8f6f\u96c5\u9ed1"])font.setPointSize(10)MainWindow.setFont(font)self.centralwidget = QWidget(MainWindow)self.centralwidget.setObjectName(u"centralwidget")self.pbDownload = QProgressBar(self.centralwidget)self.pbDownload.setObjectName(u"pbDownload")self.pbDownload.setGeometry(QRect(10, 60, 541, 31))self.pbDownload.setValue(0)self.pbDownload.setAlignment(Qt.AlignCenter)self.pbDownload.setTextVisible(False)self.label = QLabel(self.centralwidget)self.label.setObjectName(u"label")self.label.setGeometry(QRect(10, 10, 541, 41))self.label.setFont(font)self.label.setAlignment(Qt.AlignCenter)MainWindow.setCentralWidget(self.centralwidget)self.retranslateUi(MainWindow)QMetaObject.connectSlotsByName(MainWindow)# setupUidef retranslateUi(self, MainWindow):MainWindow.setWindowTitle(QCoreApplication.translate("MainWindow", u"\u5728\u7ebf\u5347\u7ea7", None))self.label.setText(QCoreApplication.translate("MainWindow", u"\u5728\u7ebf\u5347\u7ea7\u4e2d,\u8bf7\u7a0d\u7b49...", None))# retranslateUi

PyDesigner

主程序

upgrade_service.py

import timeimport configparser
import requests
import sys
import threading
import psutil
import os
import zipfile
import warningsfrom PySide6.QtWidgets import QApplication, QMainWindow
from PySide6.QtCore import Qt, QTimer
from PySide6.QtGui import QIcon, QMouseEvent
from ui.main import Ui_MainWindow
from qt_material import apply_stylesheet'''
pip install pyinstaller pyside6 qt_material psutil requestspyside6-uic -o ../../ui/main.py ../../ui/main.uipyinstaller --clean --icon=upgrade.ico D:\\1_local_project\IMVision\IMVDXUpgrade\\upgrade_service.py
pyinstaller upgrade_service.spec --noconfirm
'''warnings.filterwarnings('ignore', category=DeprecationWarning)class UpgradeInfo(object):def __init__(self):self.username = ''self.version = ''self.url = ''self.extra_file = 0self.extra_path = ''self.remark = ''class MainWindow(QMainWindow, Ui_MainWindow):def __init__(self):super(MainWindow, self).__init__()self.setupUi(self)self.setWindowFlags(Qt.FramelessWindowHint)# 开启鼠标追踪self.setMouseTracking(True)# 记录鼠标按下时的位置self.drag_start_position = Noneself.setWindowIcon(QIcon('icons/upgrade.ico'))self.label.setStyleSheet(self.label.styleSheet() + 'font-size: 20px;')self.upgrade_finished = Falseself.finished_chunk_size = 0self.total_file_count = 0threading.Thread(target=self.download_file).start()self.timer = QTimer(self)self.timer.timeout.connect(self.listen_download_state)self.timer.start(100)def mousePressEvent(self, event: QMouseEvent) -> None:if event.button() == Qt.LeftButton:self.drag_start_position = event.pos()def mouseMoveEvent(self, event: QMouseEvent) -> None:if self.drag_start_position is not None:delta = event.pos() - self.drag_start_positionself.move(self.pos() + delta)def mouseReleaseEvent(self, event: QMouseEvent) -> None:if event.button() == Qt.LeftButton:self.drag_start_position = Nonedef listen_download_state(self):if self.upgrade_finished:self.timer.stop()cf.set('upgrade', 'state', '0')cf.set('upgrade', 'currentVersion', new_version)cf.write(open('service.ini', 'w'))if self.total_file_count > 0:os.startfile(main_file)time.sleep(0.2)self.close()def updateLabel(self, c, t, overwrite=False):self.label.setText('正在升级...(' + c + '/' + t + ')') if not overwrite else self.label.setText(t)def download_file(self):upgrade_files = []self.finished_count = 0self.total_file_count = 0self.weight_file = 0self.extra_file = 0response = requests.get(upgrade_url + 'upgrade/v1/info?username=' + username, timeout=2)if response.status_code == 200:res = response.json()if res['code'] == 0 and res['data'] is not None:data = res['data']self.weight_file_tag = data['weight_file']self.extra_file_tag = data['extra_file']self.total_file_count = data['total_file_count']upgrade_files = (data['extra_path'].replace('[', '').replace(']', '').replace(' ', '').split(','))if self.total_file_count == 0:self.updateLabel('0', '当前已是最新版本!', True)time.sleep(1)self.upgrade_finished = Truereturnif self.weight_file_tag == 1:self.total_file_count += len(weight_files)self.updateLabel('0', str(self.total_file_count))time.sleep(0.2)# 下载主程序try:response = requests.get(upgrade_url + 'upgrade/v1/download?filename=' + main_file + '&username=' + username,stream=True)end_process(main_file)time.sleep(0.5)end_process(main_file)time.sleep(0.5)self.pbDownload.setMaximum(int(response.headers.get('Content-Length', 0)))with open(main_file_tmp, 'wb') as file:self.finished_chunk_size = 0for chunk in response.iter_content(chunk_size=8192 * 10):if chunk:file.write(chunk)self.finished_chunk_size += len(chunk)self.pbDownload.setValue(self.finished_chunk_size)QApplication.processEvents()time.sleep(0.5)# 下载完成,删除main_file,将临时文件改成main_fileos.remove(main_file)os.rename(main_file_tmp, main_file)except:# 下载失败,删除临时文件os.remove(main_file_tmp)self.updateLabel('0', '升级失败!请检查网络连接!', True)time.sleep(1)self.upgrade_finished = Truereturnself.updateLabel('1', str(self.total_file_count))time.sleep(0.2)self.finished_count = 1if self.weight_file_tag == 1:for weight_file in weight_files:weight_file_tmp = weight_file + '.tmp'try:# 下载权重文件response = requests.get(upgrade_url + 'upgrade/v1/download?filename=' + weight_file + '&username=' + username,stream=True)self.pbDownload.setMaximum(int(response.headers.get('Content-Length', 0)))with open('weights/' + weight_file_tmp, 'wb') as file:self.finished_chunk_size = 0for chunk in response.iter_content(chunk_size=8192 * 10):if chunk:file.write(chunk)self.finished_chunk_size += len(chunk)self.pbDownload.setValue(self.finished_chunk_size)QApplication.processEvents()time.sleep(0.5)# 下载完成,删除weight_file,将临时文件改成weight_fileos.remove('weights/' + weight_file)os.rename('weights/' + weight_file_tmp, 'weights/' + weight_file)self.finished_count += 1except:# 下载失败,删除临时文件os.remove('weights/' + weight_file_tmp)self.updateLabel('0', '升级失败!请检查网络连接!', True)time.sleep(1)self.upgrade_finished = Truereturnself.updateLabel(str(self.finished_count), str(self.total_file_count))# 最后下载第三方文件(zip格式)if self.extra_file_tag == 1:try:for idx, filename in enumerate(upgrade_files):response = requests.get(upgrade_url + 'upgrade/v1/download?filename=' + filename + '&username=' + username, stream=True)extra_file_zip = '_internal\\' + filenameself.pbDownload.setMaximum(int(response.headers.get('Content-Length', 0)))with open(extra_file_zip, 'wb') as file:self.finished_chunk_size = 0for chunk in response.iter_content(chunk_size=8192):if chunk:file.write(chunk)self.finished_chunk_size += len(chunk)self.pbDownload.setValue(self.finished_chunk_size)QApplication.processEvents()# 解压缩zipunzip_file(extra_file_zip, './_internal')self.updateLabel(str(idx + self.finished_count + 1), str(self.total_file_count))except:self.updateLabel('0', '升级失败!请检查网络连接!', True)time.sleep(1)self.upgrade_finished = Truereturnself.updateLabel('0', '升级完成!启动新版本...', True)time.sleep(0.5)self.upgrade_finished = Truedef close(self):super(MainWindow, self).close()def end_process(process_name):try:if is_process_running_by_name(process_name):os.system('taskkill /f /im ' + process_name)except:passdef is_process_running_by_name(process_name):for proc in psutil.process_iter(['name']):if proc.info['name'].find(process_name) == 0:return Truereturn Falsedef unzip_file(zip_path, extract_path='.'):if not os.path.exists(extract_path):os.makedirs(extract_path)with zipfile.ZipFile(zip_path, 'r') as zip_ref:zip_ref.extractall(extract_path)os.remove(zip_path)extra = {'font_family': '微软雅黑','density_scale': '0','button_shape': 'default','pyside6': True
}if __name__ == '__main__':cf = configparser.ConfigParser()cf_file = 'service.ini'if os.path.exists(cf_file):cf.read(cf_file)upgrade_url = cf.get('server', 'url')main_file = cf.get('upgrade', 'mainfile')weight_files = cf.get('upgrade', 'weightfiles').split(',')main_file_tmp = main_file + '.tmp'current_version = cf.get('upgrade', 'currentversion')new_version = cf.get('upgrade', 'newversion')state = cf.getint('upgrade', 'state')username = cf.get('sys', 'username')else:sys.exit(0)if state == 0 or (current_version == new_version):sys.exit(0)app = QApplication(sys.argv)main_window = MainWindow()apply_stylesheet(app, theme='dark_teal2.xml', extra=extra)main_window.show()sys.exit(app.exec())

配置文件 service.ini

后台服务(Java)

    @ApiOperation("下载升级文件")@RequestMapping("download")public void download(@RequestParam String filename, @RequestParam String username) {UpgradeSetDO upgradeSetDO = upgradeSetMapper.selectOne(new QueryWrapper<UpgradeSetDO>().eq("username", username).eq("state", 1).last(" order by id desc limit 1"));ServletRequestAttributes requestAttributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();assert requestAttributes != null;HttpServletResponse response = requestAttributes.getResponse();assert response != null;String filePath = "C:\\IMVD\\UPGRADE\\" + username + "\\" + upgradeSetDO.getVersion() + "\\" + filename;File file = new File(filePath);response.setHeader("Content-Disposition", "attachment;filename=" + filename);response.setHeader("Content-Length", String.valueOf(file.length()));try (OutputStream outputStream = response.getOutputStream();BufferedInputStream bis = new BufferedInputStream(new FileInputStream(filePath))) {byte[] buff = new byte[1024];int i = bis.read(buff);while (i != -1) {outputStream.write(buff, 0, buff.length);outputStream.flush();i = bis.read(buff);}} catch (IOException e) {log.error(e.getMessage());}}

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

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Linux 系统/etc目录下配置文件分类

目录 一、网络相关配置文件 主机名与 IP 映射类 /etc/hosts /etc/hostname 网络接口配置类 /etc/sysconfig/network-scripts/ifcfg-ens33 DNS 相关类 /etc/resolv.conf /etc/host.conf 网络服务相关类 /etc/hosts.allow文件 /etc/hosts.deny文件 /etc/netconfig …

自由学习记录(28)

C# 中的流&#xff08;Stream&#xff09; 流&#xff08;Stream&#xff09;是用于读取和写入数据的抽象基类。 流表示从数据源读取或向数据源写入数据的矢量过程。 C# 中的流类是从 System.IO.Stream 基类派生的&#xff0c;提供了多种具体实现&#xff0c;每种实现都针对…

Redis3——线程模型与数据结构

Redis3——线程模型与数据结构 本文讲述了redis的单线程模型和IO多线程工作原理&#xff0c;以及几个主要数据结构的实现。 1. Redis的单线程模型 redis6.0之前&#xff0c;一个redis进程只有一个io线程&#xff0c;通过reactor模式可以连接大量客户端&#xff1b;redis6.0为了…

Elasticsearch Serverless 现已正式发布

作者&#xff1a;来自 Elastic Yaru Lin 基于全新无状态&#xff08;stateless&#xff09;架构的 Elasticsearch Serverless 现已正式发布。它采用完全托管方式&#xff0c;因此你可以快速启动项目而无需操作或升级&#xff0c;并且可以使用最新的向量搜索和生成式 AI 功能。 …

Android CoordinatorLayout:打造高效交互界面的利器

目录 一、CoordinatorLayout 介绍及特点 二、使用方法 2.1 创建 CoordinatorLayout 布局 2.2 添加需要协调的子视图 2.3 自定义 Behavior 三、结语 相关推荐 在Android开发中&#xff0c;面对复杂多变的用户界面需求&#xff0c;CoordinatorLayout以其强大的交互管理能力…

基于Java Springboot旅游攻略APP且微信小程序

一、作品包含 源码数据库设计文档万字PPT全套环境和工具资源部署教程 二、项目技术 前端技术&#xff1a;Html、Css、Js、Vue、Element-ui 数据库&#xff1a;MySQL 后端技术&#xff1a;Java、Spring Boot、MyBatis 三、运行环境 开发工具&#xff1a;IDEA/eclipse 微信…

多模态大语言模型的对比

简介 文章主要对比了包括 VideoLLaMA 2 、CogVLM2-video 、MiniCPM-V等模型 目前主流的多模态视觉问答大模型&#xff0c;大部分采用视觉编码器、大语言模型、图像到文本特征的投影模块 目录 简介1. VideoLLaMA 21.1 网络结构1.2 STC connector具体的架构 2. MiniCPM-V 2.62.…

Android渗透环境配置教程

工具 模拟器 ADB brew install android-platform-tools set import cert # cer 证书转为 pem 证书 openssl x509 -inform DER -in cacert.der -out cacert.pem# 获取证书的 hash 值 hash$(openssl x509 -inform PEM -subject_hash_old -in cacert.pem | head -n 1)# 将 pem…

Microi吾码|.NET、VUE快速搭建项目,低代码便捷开发教程

Microi吾码&#xff5c;VUE快速搭建项目&#xff0c;低代码便捷开发教程 一、摘要二、Microi吾码介绍2.1 功能介绍2.2 团队介绍2.3 上线项目案例 三、VUE中使用Microi吾码3.1 前期了解3.2 创建第一个低代码应用3.3 接口API使用说明3.4 引擎界面可视化配置&#xff0c;生成API3.…

常见Linux命令(详解)

文章目录 常见Linux命令文件目录类命令pwd 打印当前目录的绝对路径ls 列出目录内容cd 切换路径mkdir 建立目录rmdir 删除目录touch 创建空文件cp 复制文件或目录rm 移除文件或者目录mv 移动文件与目录或重命名cat 查看文件内容more 文件分屏查看器less 分屏显示文件内容head 显…

AI - 如何构建一个大模型中的Tool

AI - 如何构建一个大模型中的Tool 大家好&#xff01;今天我们聊聊一个有趣的技术问题&#xff1a;什么是工具&#xff08;Tool&#xff09;&#xff0c;如何使用聊天模型调用工具&#xff0c;以及如何将工具的输出传递给聊天模型。我们还是基于LangChain来进行讨论&#xff0…

【测试工具JMeter篇】JMeter性能测试入门级教程(四):JMeter中BeanShell内置方法使用

一、什么是BeanShell BeanShell是一种完全符合Java语法规范的脚本语言,并且又拥有自己的一些语法和方法;BeanShell是一种松散类型的脚本语言(这点和JS类似);BeanShell是用Java写成的,一个小型的、免费的、可以下载的、嵌入式的Java源代码解释器,具有对象脚本语言特性,非常精简…

MyBatis异常体系中ErrorContext和ExceptionFactory原理分析

&#x1f3ae; 作者主页&#xff1a;点击 &#x1f381; 完整专栏和代码&#xff1a;点击 &#x1f3e1; 博客主页&#xff1a;点击 文章目录 exceptions包分包设计ExceptionFactory类介绍为什么使用工厂不是直接new呢&#xff1f;【统一的异常处理机制】【异常的封装与转化】【…

白鹿 Hands-on:消除冷启动——基于 Amazon Lambda SnapStart 轻松打造 Serverless Web 应用(二)

文章目录 前言一、前文回顾二、在 Lambda 上运行2.1、查看 Amazon SAM template2.2、编译和部署到 Amazon Lambda2.3、功能测试与验证 三、对比 Snapstart 效果四、资源清理五、实验总结总结 前言 在这个环节中&#xff0c;我们将延续《白鹿 Hands-on&#xff1a;消除冷启动——…

Spring Shell如何与SpringBoot集成并快速创建命令行界面 (CLI) 应用程序

Spring Shell 介绍 Spring Shell 是一个强大的工具&#xff0c;可用于构建命令行应用程序&#xff0c;提供了简单的方式来创建和管理交互式 CLI。它适合那些希望通过命令行与 Java 应用程序进行交互的开发者&#xff0c;尤其是在需要自动化、交互式输入或与 Spring 生态系统集…

齐护机器人ModbusRTU RS485转TTL通信模块与ESP32 Arduino通信可Mixly的图形化编程Scratch图形化编程

齐护机器人ModbusRTU RS485-TTL通信模块 一、概念理解 Modbus协议是一种由Modicon公司&#xff08;现为施耐德电气Schneider Electric&#xff09;于1979年发表的网络通信协议&#xff0c;旨在实现可编辑逻辑控制器&#xff08;PLC&#xff09;之间的通信。 1.1 什么是Mod…

K8S版本和istio版本的对照关系

版本对照关系 下载地址1 下载地址2

vue-cli创建项目报错:command failed: npm install --loglevel error

网上解决方法有很多&#xff0c;对于我都没用。 最后用这个方法起了作用&#xff1a; 尝试将npm源设置为HTTP&#xff0c;慎用&#xff0c;可能不安全 npm config set registry http://registry.npm.taobao.org/ 改为http就顺利创建项目了。

数据结构自测题6

第7章 图 自测卷解答 一、单选题&#xff08;每题1分&#xff0c;共16分&#xff09; &#xff08; C &#xff09;1. 在一个图中&#xff0c;所有顶点的度数之和等于图的边数的 倍。 A&#xff0e;1/2 B. 1 C. 2 D. 4 &#xff08; B &#xff09;2. 在一个有向图中&#xff0…

洛谷P1305 新二叉树(c嘎嘎)

题目链接&#xff1a;P1305 新二叉树 - 洛谷 | 计算机科学教育新生态 题目难度&#xff1a;普及 刷题心得&#xff1a;做了几道这种类型的题都不用建树就可以解决&#xff0c;基本上还是利用好树的结构&#xff0c;例如这道题求前序序列&#xff08;根左右&#xff09;是可以用…