feat: 优化更新下载界面 v3.4.2 #patch - 1.优化下载进度对话框布局和样式 2.增大信息显示区域,提升可读性 3.美化进度条和状态显示 4.添加实时下载速度和剩余时间显示 5.更新版本截图
This commit is contained in:
BIN
banbenjietu.png
BIN
banbenjietu.png
Binary file not shown.
|
Before Width: | Height: | Size: 47 KiB After Width: | Height: | Size: 56 KiB |
@@ -10,6 +10,8 @@ from PyQt5.QtWidgets import (QMainWindow, QWidget, QVBoxLayout, QHBoxLayout,
|
||||
from PyQt5.QtCore import Qt, QTimer, QThread, pyqtSignal
|
||||
from PyQt5.QtGui import QIcon, QPixmap
|
||||
import time
|
||||
import requests
|
||||
from urllib.parse import quote
|
||||
|
||||
sys.path.append(str(Path(__file__).parent.parent))
|
||||
|
||||
@@ -152,6 +154,150 @@ class UpdateWorker(QThread):
|
||||
except Exception as e:
|
||||
self.finished.emit((False, False, str(e)))
|
||||
|
||||
class DownloadProgressDialog(QDialog):
|
||||
"""下载进度对话框"""
|
||||
def __init__(self, parent=None):
|
||||
super().__init__(parent)
|
||||
self.setWindowTitle("正在下载更新")
|
||||
self.setFixedSize(400, 300)
|
||||
self.setWindowFlags(Qt.Dialog | Qt.CustomizeWindowHint | Qt.WindowTitleHint)
|
||||
|
||||
layout = QVBoxLayout()
|
||||
|
||||
# 添加图标
|
||||
icon_label = QLabel()
|
||||
icon_label.setPixmap(self.style().standardIcon(QStyle.SP_DesktopIcon).pixmap(32, 32))
|
||||
icon_label.setAlignment(Qt.AlignCenter)
|
||||
layout.addWidget(icon_label)
|
||||
|
||||
# 下载状态标签
|
||||
self.status_label = QLabel("正在连接服务器...")
|
||||
self.status_label.setAlignment(Qt.AlignCenter)
|
||||
self.status_label.setStyleSheet("""
|
||||
color: #0d6efd;
|
||||
font-size: 14px;
|
||||
font-weight: bold;
|
||||
padding: 10px;
|
||||
""")
|
||||
layout.addWidget(self.status_label)
|
||||
|
||||
# 进度条
|
||||
self.progress_bar = QProgressBar()
|
||||
self.progress_bar.setStyleSheet("""
|
||||
QProgressBar {
|
||||
border: 2px solid #e9ecef;
|
||||
border-radius: 5px;
|
||||
text-align: center;
|
||||
min-height: 20px;
|
||||
background-color: #f8f9fa;
|
||||
}
|
||||
QProgressBar::chunk {
|
||||
background-color: #0d6efd;
|
||||
border-radius: 3px;
|
||||
}
|
||||
""")
|
||||
layout.addWidget(self.progress_bar)
|
||||
|
||||
# 下载信息框
|
||||
info_frame = QFrame()
|
||||
info_frame.setStyleSheet("""
|
||||
QFrame {
|
||||
background-color: #f8f9fa;
|
||||
border-radius: 8px;
|
||||
border: 1px solid #dee2e6;
|
||||
margin: 10px;
|
||||
padding: 20px;
|
||||
}
|
||||
QLabel {
|
||||
color: #495057;
|
||||
font-size: 14px;
|
||||
padding: 8px;
|
||||
margin: 2px;
|
||||
background: white;
|
||||
border-radius: 4px;
|
||||
border: 1px solid #e9ecef;
|
||||
}
|
||||
""")
|
||||
info_layout = QVBoxLayout(info_frame)
|
||||
info_layout.setSpacing(10) # 增加标签之间的间距
|
||||
|
||||
# 下载速度
|
||||
self.speed_label = QLabel("下载速度: --")
|
||||
self.speed_label.setMinimumHeight(35) # 设置最小高度
|
||||
info_layout.addWidget(self.speed_label)
|
||||
|
||||
# 文件大小
|
||||
self.size_label = QLabel("文件大小: --")
|
||||
self.size_label.setMinimumHeight(35) # 设置最小高度
|
||||
info_layout.addWidget(self.size_label)
|
||||
|
||||
# 预计剩余时间
|
||||
self.time_label = QLabel("预计剩余时间: --")
|
||||
self.time_label.setMinimumHeight(35) # 设置最小高度
|
||||
info_layout.addWidget(self.time_label)
|
||||
|
||||
layout.addWidget(info_frame)
|
||||
|
||||
self.setLayout(layout)
|
||||
|
||||
# 初始化变量
|
||||
self.start_time = time.time()
|
||||
self.last_update_time = time.time()
|
||||
self.last_downloaded = 0
|
||||
|
||||
def update_progress(self, downloaded_size, total_size):
|
||||
"""更新进度信息"""
|
||||
if total_size > 0:
|
||||
percentage = (downloaded_size / total_size) * 100
|
||||
self.progress_bar.setValue(int(percentage))
|
||||
|
||||
# 计算下载速度
|
||||
current_time = time.time()
|
||||
time_diff = current_time - self.last_update_time
|
||||
if time_diff >= 0.5: # 每0.5秒更新一次
|
||||
speed = (downloaded_size - self.last_downloaded) / time_diff
|
||||
self.last_downloaded = downloaded_size
|
||||
self.last_update_time = current_time
|
||||
|
||||
# 更新下载信息
|
||||
speed_text = self._format_speed(speed)
|
||||
self.speed_label.setText(f"下载速度: {speed_text}")
|
||||
|
||||
# 更新文件大小信息
|
||||
total_mb = total_size / (1024 * 1024)
|
||||
downloaded_mb = downloaded_size / (1024 * 1024)
|
||||
self.size_label.setText(f"文件大小: {downloaded_mb:.1f} MB / {total_mb:.1f} MB")
|
||||
|
||||
# 更新预计剩余时间
|
||||
if speed > 0:
|
||||
remaining_bytes = total_size - downloaded_size
|
||||
remaining_time = remaining_bytes / speed
|
||||
time_text = self._format_time(remaining_time)
|
||||
self.time_label.setText(f"预计剩余时间: {time_text}")
|
||||
|
||||
# 更新状态文本
|
||||
self.status_label.setText(f"正在下载更新... {percentage:.1f}%")
|
||||
|
||||
def _format_speed(self, speed_bytes):
|
||||
"""格式化速度显示"""
|
||||
if speed_bytes > 1024 * 1024:
|
||||
return f"{speed_bytes / (1024 * 1024):.1f} MB/s"
|
||||
elif speed_bytes > 1024:
|
||||
return f"{speed_bytes / 1024:.1f} KB/s"
|
||||
else:
|
||||
return f"{speed_bytes:.1f} B/s"
|
||||
|
||||
def _format_time(self, seconds):
|
||||
"""格式化时间显示"""
|
||||
if seconds < 60:
|
||||
return f"{seconds:.0f}秒"
|
||||
elif seconds < 3600:
|
||||
minutes = seconds / 60
|
||||
return f"{minutes:.0f}分钟"
|
||||
else:
|
||||
hours = seconds / 3600
|
||||
return f"{hours:.1f}小时"
|
||||
|
||||
class MainWindow(QMainWindow):
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
@@ -787,7 +933,6 @@ class MainWindow(QMainWindow):
|
||||
border-radius: 4px;
|
||||
font-size: 13px;
|
||||
min-width: 100px;
|
||||
margin: 10px;
|
||||
}
|
||||
QPushButton:hover {
|
||||
background-color: #bb2d3b;
|
||||
@@ -1623,33 +1768,222 @@ class MainWindow(QMainWindow):
|
||||
return
|
||||
|
||||
try:
|
||||
# 创建下载目录
|
||||
download_dir = Path.home() / "Downloads" / "CursorHelper"
|
||||
# 创建下载目录(优先使用D盘,如果不存在则使用当前程序目录)
|
||||
if Path("D:/").exists():
|
||||
download_dir = Path("D:/CursorHelper/updates")
|
||||
else:
|
||||
download_dir = Path(__file__).parent.parent / "updates"
|
||||
download_dir.mkdir(parents=True, exist_ok=True)
|
||||
|
||||
# 下载文件名
|
||||
file_name = download_url.split('/')[-1]
|
||||
save_path = download_dir / file_name
|
||||
|
||||
self.show_loading_dialog("正在下载更新...")
|
||||
# 创建并显示进度对话框
|
||||
progress_dialog = DownloadProgressDialog(self)
|
||||
progress_dialog.show()
|
||||
|
||||
# 开始下载
|
||||
success, message = self.version_manager.download_update(download_url, str(save_path))
|
||||
self.hide_loading_dialog()
|
||||
|
||||
if success:
|
||||
self.show_custom_message(
|
||||
"下载完成",
|
||||
"更新包下载成功",
|
||||
f"更新包已下载到:\n{save_path}\n\n请关闭程序后运行更新包完成更新。",
|
||||
QStyle.SP_DialogApplyButton,
|
||||
"#198754"
|
||||
try:
|
||||
# 处理下载地址中的中文字符
|
||||
url_parts = download_url.split('/')
|
||||
url_parts[-1] = quote(url_parts[-1])
|
||||
encoded_url = '/'.join(url_parts)
|
||||
|
||||
# 设置请求头
|
||||
headers = {
|
||||
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/121.0.0.0 Safari/537.36',
|
||||
'Accept': '*/*',
|
||||
'Accept-Encoding': 'gzip, deflate, br',
|
||||
'Connection': 'keep-alive'
|
||||
}
|
||||
|
||||
response = requests.get(
|
||||
encoded_url,
|
||||
stream=True,
|
||||
headers=headers,
|
||||
timeout=30
|
||||
)
|
||||
# 退出程序
|
||||
self.quit_application()
|
||||
else:
|
||||
self.show_custom_error("下载失败", message)
|
||||
response.raise_for_status()
|
||||
|
||||
# 获取文件大小
|
||||
total_size = int(response.headers.get('content-length', 0))
|
||||
if total_size == 0:
|
||||
progress_dialog.hide()
|
||||
self.show_custom_error("下载失败", "无法获取文件大小,下载地址可能无效")
|
||||
return False, "无法获取文件大小"
|
||||
|
||||
# 更新进度条范围
|
||||
progress_dialog.progress_bar.setRange(0, 100)
|
||||
|
||||
# 下载文件
|
||||
downloaded_size = 0
|
||||
block_size = 8192
|
||||
|
||||
with open(save_path, 'wb') as f:
|
||||
for chunk in response.iter_content(chunk_size=block_size):
|
||||
if chunk:
|
||||
f.write(chunk)
|
||||
downloaded_size += len(chunk)
|
||||
# 更新进度
|
||||
progress_dialog.update_progress(downloaded_size, total_size)
|
||||
QApplication.processEvents() # 保持界面响应
|
||||
|
||||
# 验证文件大小
|
||||
actual_size = os.path.getsize(save_path)
|
||||
if actual_size != total_size:
|
||||
progress_dialog.hide()
|
||||
os.remove(save_path)
|
||||
self.show_custom_error("下载失败", "文件下载不完整,请重试")
|
||||
return False, "文件下载不完整"
|
||||
|
||||
progress_dialog.hide()
|
||||
|
||||
# 显示下载完成对话框
|
||||
self._show_download_complete_dialog(save_path)
|
||||
return True, "下载成功"
|
||||
|
||||
except requests.exceptions.Timeout:
|
||||
progress_dialog.hide()
|
||||
self.show_custom_error("下载失败", "下载超时,请检查网络连接后重试")
|
||||
return False, "下载超时"
|
||||
except requests.exceptions.RequestException as e:
|
||||
progress_dialog.hide()
|
||||
self.show_custom_error("下载失败", f"下载出错: {str(e)}")
|
||||
return False, str(e)
|
||||
except Exception as e:
|
||||
progress_dialog.hide()
|
||||
self.show_custom_error("下载失败", f"下载过程中发生错误: {str(e)}")
|
||||
return False, str(e)
|
||||
|
||||
except Exception as e:
|
||||
self.hide_loading_dialog()
|
||||
self.show_custom_error("下载失败", f"下载更新时发生错误: {str(e)}")
|
||||
self.show_custom_error("下载失败", f"下载更新时发生错误: {str(e)}")
|
||||
return False, str(e)
|
||||
|
||||
def _show_download_complete_dialog(self, save_path):
|
||||
"""显示下载完成对话框"""
|
||||
# 创建自定义消息框
|
||||
msg = QDialog(self)
|
||||
msg.setWindowTitle("下载完成")
|
||||
msg.setFixedWidth(500)
|
||||
msg.setWindowFlags(msg.windowFlags() & ~Qt.WindowContextHelpButtonHint)
|
||||
|
||||
layout = QVBoxLayout()
|
||||
|
||||
# 添加图标
|
||||
icon_label = QLabel()
|
||||
icon_label.setPixmap(self.style().standardIcon(QStyle.SP_DialogApplyButton).pixmap(32, 32))
|
||||
icon_label.setAlignment(Qt.AlignCenter)
|
||||
layout.addWidget(icon_label)
|
||||
|
||||
# 添加标题
|
||||
title_label = QLabel("更新包下载成功")
|
||||
title_label.setAlignment(Qt.AlignCenter)
|
||||
title_label.setStyleSheet("""
|
||||
font-size: 16px;
|
||||
font-weight: bold;
|
||||
color: #198754;
|
||||
padding: 10px;
|
||||
""")
|
||||
layout.addWidget(title_label)
|
||||
|
||||
# 添加文件信息框
|
||||
info_frame = QFrame()
|
||||
info_frame.setStyleSheet("""
|
||||
QFrame {
|
||||
background-color: #f8f9fa;
|
||||
border-radius: 8px;
|
||||
border: 1px solid #dee2e6;
|
||||
margin: 10px;
|
||||
padding: 15px;
|
||||
}
|
||||
QLabel {
|
||||
color: #333333;
|
||||
font-size: 14px;
|
||||
padding: 5px;
|
||||
}
|
||||
""")
|
||||
info_layout = QVBoxLayout(info_frame)
|
||||
|
||||
# 文件路径
|
||||
path_label = QLabel(f"文件保存在:\n{save_path}")
|
||||
path_label.setWordWrap(True)
|
||||
path_label.setTextInteractionFlags(Qt.TextSelectableByMouse)
|
||||
info_layout.addWidget(path_label)
|
||||
|
||||
# 文件大小
|
||||
size_mb = save_path.stat().st_size / (1024 * 1024)
|
||||
size_label = QLabel(f"文件大小:{size_mb:.2f} MB")
|
||||
info_layout.addWidget(size_label)
|
||||
|
||||
layout.addWidget(info_frame)
|
||||
|
||||
# 提示信息
|
||||
tip_label = QLabel("请关闭程序后运行更新包完成更新。")
|
||||
tip_label.setStyleSheet("color: #dc3545; font-weight: bold; padding: 10px;")
|
||||
layout.addWidget(tip_label)
|
||||
|
||||
# 按钮区域
|
||||
btn_layout = QHBoxLayout()
|
||||
|
||||
# 打开文件按钮
|
||||
open_file_btn = QPushButton("打开文件")
|
||||
open_file_btn.setStyleSheet("""
|
||||
QPushButton {
|
||||
background-color: #0d6efd;
|
||||
color: white;
|
||||
border: none;
|
||||
padding: 8px 20px;
|
||||
border-radius: 4px;
|
||||
font-size: 13px;
|
||||
min-width: 100px;
|
||||
}
|
||||
QPushButton:hover {
|
||||
background-color: #0b5ed7;
|
||||
}
|
||||
""")
|
||||
open_file_btn.clicked.connect(lambda: os.startfile(str(save_path)))
|
||||
btn_layout.addWidget(open_file_btn)
|
||||
|
||||
# 打开文件夹按钮
|
||||
open_dir_btn = QPushButton("打开文件夹")
|
||||
open_dir_btn.setStyleSheet("""
|
||||
QPushButton {
|
||||
background-color: #198754;
|
||||
color: white;
|
||||
border: none;
|
||||
padding: 8px 20px;
|
||||
border-radius: 4px;
|
||||
font-size: 13px;
|
||||
min-width: 100px;
|
||||
}
|
||||
QPushButton:hover {
|
||||
background-color: #157347;
|
||||
}
|
||||
""")
|
||||
open_dir_btn.clicked.connect(lambda: os.startfile(str(save_path.parent)))
|
||||
btn_layout.addWidget(open_dir_btn)
|
||||
|
||||
# 退出按钮
|
||||
quit_btn = QPushButton("立即退出")
|
||||
quit_btn.setStyleSheet("""
|
||||
QPushButton {
|
||||
background-color: #dc3545;
|
||||
color: white;
|
||||
border: none;
|
||||
padding: 8px 20px;
|
||||
border-radius: 4px;
|
||||
font-size: 13px;
|
||||
min-width: 100px;
|
||||
font-weight: bold;
|
||||
}
|
||||
QPushButton:hover {
|
||||
background-color: #bb2d3b;
|
||||
}
|
||||
""")
|
||||
quit_btn.clicked.connect(lambda: (msg.accept(), self.quit_application()))
|
||||
btn_layout.addWidget(quit_btn)
|
||||
|
||||
layout.addLayout(btn_layout)
|
||||
msg.setLayout(layout)
|
||||
msg.exec_()
|
||||
Reference in New Issue
Block a user