#!/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_())