[minor] 新增自动更新功能 模块Test
This commit is contained in:
290
update_dialog.py
Normal file
290
update_dialog.py
Normal file
@@ -0,0 +1,290 @@
|
||||
#!/usr/bin/env python3
|
||||
# -*- coding: utf-8 -*-
|
||||
"""
|
||||
更新进度对话框
|
||||
显示下载进度、重试信息和状态提示
|
||||
"""
|
||||
|
||||
from PyQt5.QtWidgets import (QDialog, QVBoxLayout, QLabel,
|
||||
QPushButton, QProgressBar, QHBoxLayout)
|
||||
from PyQt5.QtCore import Qt
|
||||
from PyQt5.QtGui import QFont
|
||||
|
||||
|
||||
class UpdateProgressDialog(QDialog):
|
||||
"""
|
||||
更新下载进度对话框
|
||||
|
||||
特性:
|
||||
- 实时显示下载进度
|
||||
- 显示重试状态
|
||||
- 支持用户取消
|
||||
- 现代化UI设计
|
||||
"""
|
||||
|
||||
def __init__(self, version, parent=None):
|
||||
super().__init__(parent)
|
||||
self.version = version
|
||||
self.downloader = None
|
||||
self.init_ui()
|
||||
|
||||
def init_ui(self):
|
||||
"""初始化UI"""
|
||||
self.setWindowTitle("正在更新")
|
||||
self.setFixedWidth(450)
|
||||
# 禁止关闭按钮(只能通过取消按钮关闭)
|
||||
self.setWindowFlags(Qt.Dialog | Qt.WindowTitleHint | Qt.CustomizeWindowHint)
|
||||
|
||||
layout = QVBoxLayout()
|
||||
layout.setSpacing(15)
|
||||
layout.setContentsMargins(25, 20, 25, 20)
|
||||
|
||||
# 标题
|
||||
self.title_label = QLabel(f"正在下载 v{self.version}")
|
||||
self.title_label.setFont(QFont('Microsoft YaHei', 12, QFont.Bold))
|
||||
self.title_label.setAlignment(Qt.AlignCenter)
|
||||
layout.addWidget(self.title_label)
|
||||
|
||||
# 进度条
|
||||
self.progress_bar = QProgressBar()
|
||||
self.progress_bar.setMinimum(0)
|
||||
self.progress_bar.setMaximum(100)
|
||||
self.progress_bar.setValue(0)
|
||||
self.progress_bar.setTextVisible(True)
|
||||
self.progress_bar.setFormat("%p%")
|
||||
layout.addWidget(self.progress_bar)
|
||||
|
||||
# 状态文本
|
||||
self.status_label = QLabel("准备下载...")
|
||||
self.status_label.setAlignment(Qt.AlignCenter)
|
||||
self.status_label.setStyleSheet("color: #666; font-size: 10px;")
|
||||
self.status_label.setMinimumHeight(20)
|
||||
layout.addWidget(self.status_label)
|
||||
|
||||
# 重试信息标签(默认隐藏)
|
||||
self.retry_label = QLabel("")
|
||||
self.retry_label.setAlignment(Qt.AlignCenter)
|
||||
self.retry_label.setStyleSheet("color: #ff9800; font-size: 10px; font-weight: bold;")
|
||||
self.retry_label.setMinimumHeight(20)
|
||||
self.retry_label.hide()
|
||||
layout.addWidget(self.retry_label)
|
||||
|
||||
# 按钮布局
|
||||
button_layout = QHBoxLayout()
|
||||
button_layout.addStretch()
|
||||
|
||||
self.cancel_button = QPushButton("取消")
|
||||
self.cancel_button.setFixedWidth(100)
|
||||
self.cancel_button.clicked.connect(self.cancel_download)
|
||||
button_layout.addWidget(self.cancel_button)
|
||||
|
||||
button_layout.addStretch()
|
||||
layout.addLayout(button_layout)
|
||||
|
||||
self.setLayout(layout)
|
||||
|
||||
# 应用样式
|
||||
self.apply_styles()
|
||||
|
||||
def apply_styles(self):
|
||||
"""应用现代化样式"""
|
||||
self.setStyleSheet("""
|
||||
QDialog {
|
||||
background: qlineargradient(
|
||||
x1:0, y1:0, x2:0, y2:1,
|
||||
stop:0 #f8fafb,
|
||||
stop:1 #e8ecef
|
||||
);
|
||||
}
|
||||
QLabel {
|
||||
background: transparent;
|
||||
}
|
||||
QProgressBar {
|
||||
border: 2px solid #ddd;
|
||||
border-radius: 8px;
|
||||
text-align: center;
|
||||
height: 28px;
|
||||
background: white;
|
||||
font-size: 11px;
|
||||
font-weight: bold;
|
||||
}
|
||||
QProgressBar::chunk {
|
||||
background: qlineargradient(x1:0, y1:0, x2:1, y2:0,
|
||||
stop:0 #4285f4,
|
||||
stop:0.5 #1976d2,
|
||||
stop:1 #1565c0);
|
||||
border-radius: 6px;
|
||||
}
|
||||
QPushButton {
|
||||
background: qlineargradient(
|
||||
x1:0, y1:0, x2:0, y2:1,
|
||||
stop:0 #f5f5f5,
|
||||
stop:1 #e0e0e0
|
||||
);
|
||||
border: 1px solid #ccc;
|
||||
border-radius: 6px;
|
||||
padding: 8px 20px;
|
||||
font-size: 11px;
|
||||
font-family: 'Microsoft YaHei';
|
||||
}
|
||||
QPushButton:hover {
|
||||
background: qlineargradient(
|
||||
x1:0, y1:0, x2:0, y2:1,
|
||||
stop:0 #e8e8e8,
|
||||
stop:1 #d0d0d0
|
||||
);
|
||||
border: 1px solid #999;
|
||||
}
|
||||
QPushButton:pressed {
|
||||
background: #d0d0d0;
|
||||
}
|
||||
""")
|
||||
|
||||
def update_progress(self, downloaded, total):
|
||||
"""
|
||||
更新下载进度
|
||||
|
||||
Args:
|
||||
downloaded: 已下载字节数
|
||||
total: 总字节数
|
||||
"""
|
||||
if total > 0:
|
||||
# 计算百分比
|
||||
progress = int((downloaded / total) * 100)
|
||||
self.progress_bar.setValue(progress)
|
||||
|
||||
# 转换为MB显示
|
||||
downloaded_mb = downloaded / (1024 * 1024)
|
||||
total_mb = total / (1024 * 1024)
|
||||
|
||||
# 更新状态文本
|
||||
self.status_label.setText(f"已下载 {downloaded_mb:.1f} MB / {total_mb:.1f} MB")
|
||||
|
||||
# 更新进度条格式
|
||||
self.progress_bar.setFormat(f"%p% ({downloaded_mb:.1f}/{total_mb:.1f} MB)")
|
||||
else:
|
||||
# 无法获取总大小时显示不确定进度
|
||||
self.progress_bar.setMaximum(0)
|
||||
self.progress_bar.setFormat("正在下载...")
|
||||
self.status_label.setText("正在下载,请稍候...")
|
||||
|
||||
def show_retry_info(self, current_retry, max_retries):
|
||||
"""
|
||||
显示重试信息
|
||||
|
||||
Args:
|
||||
current_retry: 当前重试次数
|
||||
max_retries: 最大重试次数
|
||||
"""
|
||||
self.retry_label.setText(f"⚠️ 下载失败,正在重试... ({current_retry}/{max_retries})")
|
||||
self.retry_label.show()
|
||||
|
||||
# 重置进度条
|
||||
self.progress_bar.setValue(0)
|
||||
self.status_label.setText("等待重试...")
|
||||
|
||||
# 更新标题
|
||||
self.title_label.setText(f"正在重试下载 v{self.version}")
|
||||
|
||||
def download_finished(self, file_path):
|
||||
"""
|
||||
下载完成
|
||||
|
||||
Args:
|
||||
file_path: 下载的文件路径
|
||||
"""
|
||||
self.title_label.setText(f"✅ 下载完成 v{self.version}")
|
||||
self.status_label.setText("下载完成,正在准备安装...")
|
||||
self.status_label.setStyleSheet("color: #28a745; font-size: 10px; font-weight: bold;")
|
||||
self.progress_bar.setValue(100)
|
||||
self.progress_bar.setFormat("100% (完成)")
|
||||
self.cancel_button.setEnabled(False)
|
||||
self.retry_label.hide()
|
||||
|
||||
def download_error(self, error_msg):
|
||||
"""
|
||||
下载失败
|
||||
|
||||
Args:
|
||||
error_msg: 错误信息
|
||||
"""
|
||||
self.title_label.setText(f"❌ 下载失败")
|
||||
|
||||
# 错误信息截断(避免太长)
|
||||
if len(error_msg) > 80:
|
||||
display_msg = error_msg[:80] + "..."
|
||||
else:
|
||||
display_msg = error_msg
|
||||
|
||||
self.status_label.setText(display_msg)
|
||||
self.status_label.setStyleSheet("color: #dc3545; font-size: 10px; font-weight: bold;")
|
||||
self.cancel_button.setText("关闭")
|
||||
self.retry_label.hide()
|
||||
|
||||
# 进度条变红
|
||||
self.progress_bar.setStyleSheet("""
|
||||
QProgressBar {
|
||||
border: 2px solid #dc3545;
|
||||
border-radius: 8px;
|
||||
text-align: center;
|
||||
height: 28px;
|
||||
background: white;
|
||||
}
|
||||
QProgressBar::chunk {
|
||||
background: #dc3545;
|
||||
border-radius: 6px;
|
||||
}
|
||||
""")
|
||||
|
||||
def cancel_download(self):
|
||||
"""取消下载"""
|
||||
if self.downloader and self.downloader.isRunning():
|
||||
# 确认取消
|
||||
from PyQt5.QtWidgets import QMessageBox
|
||||
reply = QMessageBox.question(
|
||||
self,
|
||||
"确认取消",
|
||||
"确定要取消下载吗?",
|
||||
QMessageBox.Yes | QMessageBox.No,
|
||||
QMessageBox.No
|
||||
)
|
||||
|
||||
if reply == QMessageBox.Yes:
|
||||
self.downloader.cancel()
|
||||
self.downloader.wait()
|
||||
self.status_label.setText("下载已取消")
|
||||
self.reject()
|
||||
else:
|
||||
# 下载已完成或出错,直接关闭
|
||||
self.reject()
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
# 测试代码
|
||||
import sys
|
||||
from PyQt5.QtWidgets import QApplication
|
||||
|
||||
app = QApplication(sys.argv)
|
||||
|
||||
# 创建测试对话框
|
||||
dialog = UpdateProgressDialog("1.5.53")
|
||||
|
||||
# 模拟下载进度
|
||||
dialog.show()
|
||||
|
||||
# 测试进度更新
|
||||
import time
|
||||
from PyQt5.QtCore import QTimer
|
||||
|
||||
def test_progress():
|
||||
for i in range(0, 101, 10):
|
||||
dialog.update_progress(i * 1024 * 1024, 100 * 1024 * 1024)
|
||||
QApplication.processEvents()
|
||||
time.sleep(0.2)
|
||||
|
||||
dialog.download_finished("/tmp/test.exe")
|
||||
|
||||
QTimer.singleShot(500, test_progress)
|
||||
|
||||
sys.exit(app.exec_())
|
||||
|
||||
Reference in New Issue
Block a user