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)
# setupUi
def 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 time
import configparser
import requests
import sys
import threading
import psutil
import os
import zipfile
import warnings
from 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 requests
pyside6-uic -o ../../ui/main.py ../../ui/main.ui
pyinstaller --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 = 0
self.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 = None
self.setWindowIcon(QIcon('icons/upgrade.ico'))
self.label.setStyleSheet(self.label.styleSheet() + 'font-size: 20px;')
self.upgrade_finished = False
self.finished_chunk_size = 0
self.total_file_count = 0
threading.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_position
self.move(self.pos() + delta)
def mouseReleaseEvent(self, event: QMouseEvent) -> None:
if event.button() == Qt.LeftButton:
self.drag_start_position = None
def 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 = 0
self.total_file_count = 0
self.weight_file = 0
self.extra_file = 0
response = 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 = True
return
if 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 = 0
for 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_file
os.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 = True
return
self.updateLabel('1', str(self.total_file_count))
time.sleep(0.2)
self.finished_count = 1
if 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 = 0
for 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_file
os.remove('weights/' + weight_file)
os.rename('weights/' + weight_file_tmp, 'weights/' + weight_file)
self.finished_count += 1
except:
# 下载失败,删除临时文件
os.remove('weights/' + weight_file_tmp)
self.updateLabel('0', '升级失败!请检查网络连接!', True)
time.sleep(1)
self.upgrade_finished = True
return
self.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\\' + filename
self.pbDownload.setMaximum(int(response.headers.get('Content-Length', 0)))
with open(extra_file_zip, 'wb') as file:
self.finished_chunk_size = 0
for 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()
# 解压缩zip
unzip_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 = True
return
self.updateLabel('0', '升级完成!启动新版本...', True)
time.sleep(0.5)
self.upgrade_finished = True
def 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:
pass
def is_process_running_by_name(process_name):
for proc in psutil.process_iter(['name']):
if proc.info['name'].find(process_name) == 0:
return True
return False
def 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());
}
}