#!/usr/bin/env python3 # -*- coding: utf-8 -*- """ 自定义版本更新对话框 美观的布局和用户体验 """ from PyQt5.QtWidgets import (QDialog, QVBoxLayout, QHBoxLayout, QLabel, QPushButton, QTextEdit, QFrame) from PyQt5.QtCore import Qt from PyQt5.QtGui import QFont, QCursor class UpdateNotificationDialog(QDialog): """ 版本更新提示对话框 布局: - 标题区 - 更新内容区 - 下载地址区(可复制) - 按钮区(两行,美观布局) """ # 用户选择(返回值) CHOICE_UPDATE_NOW = 1 # 立即更新 CHOICE_UPDATE_LATER = 2 # 稍后更新 CHOICE_IGNORE = 3 # 忽略此版本 def __init__(self, version, download_url, update_content="", parent=None): super().__init__(parent) self.version = version self.download_url = download_url self.update_content = update_content self.user_choice = None self.init_ui() def init_ui(self): """初始化UI""" self.setWindowTitle("版本更新") self.setFixedWidth(550) self.setMinimumHeight(400) # 禁用关闭按钮(只能通过按钮关闭) self.setWindowFlags(Qt.Dialog | Qt.WindowTitleHint | Qt.CustomizeWindowHint) # 主布局 layout = QVBoxLayout() layout.setSpacing(15) layout.setContentsMargins(25, 20, 25, 20) # ============ 标题区 ============ title_label = QLabel(f"🔔 发现新版本 v{self.version}") title_label.setFont(QFont('Microsoft YaHei', 14, QFont.Bold)) title_label.setAlignment(Qt.AlignCenter) title_label.setStyleSheet("color: #2c3e50; margin-bottom: 5px;") layout.addWidget(title_label) # 分隔线 line1 = QFrame() line1.setFrameShape(QFrame.HLine) line1.setStyleSheet("background: #ddd; max-height: 1px;") layout.addWidget(line1) # ============ 更新内容区(可选)============ # 🔥 只有在有更新内容时才显示 if self.update_content and self.update_content.strip(): content_label = QLabel("📝 更新内容:") content_label.setFont(QFont('Microsoft YaHei', 10, QFont.Bold)) content_label.setStyleSheet("color: #34495e;") layout.addWidget(content_label) # 更新内容文本 content_text = QTextEdit() content_text.setReadOnly(True) content_text.setMaximumHeight(100) content_text.setStyleSheet(""" QTextEdit { border: 1px solid #ddd; border-radius: 6px; padding: 8px; background: #f8f9fa; font-size: 11px; color: #555; } """) content_text.setText(self.update_content) layout.addWidget(content_text) # ============ 下载地址区 ============ url_label = QLabel("📥 下载地址:") url_label.setFont(QFont('Microsoft YaHei', 10, QFont.Bold)) url_label.setStyleSheet("color: #34495e; margin-top: 5px;") layout.addWidget(url_label) # 下载地址文本框(可选择复制) self.url_text = QTextEdit() self.url_text.setReadOnly(True) self.url_text.setMaximumHeight(60) self.url_text.setText(self.download_url) self.url_text.setStyleSheet(""" QTextEdit { border: 2px solid #4285f4; border-radius: 6px; padding: 8px; background: #e3f2fd; font-size: 10px; color: #1565c0; font-family: 'Consolas', 'Courier New', monospace; } """) # 全选文本,方便复制 self.url_text.selectAll() layout.addWidget(self.url_text) # 复制提示 copy_hint = QLabel("💡 提示:上方地址已自动选中,按 Ctrl+C 即可复制") copy_hint.setFont(QFont('Microsoft YaHei', 8)) copy_hint.setStyleSheet("color: #7f8c8d;") layout.addWidget(copy_hint) # 分隔线 line2 = QFrame() line2.setFrameShape(QFrame.HLine) line2.setStyleSheet("background: #ddd; max-height: 1px; margin-top: 10px;") layout.addWidget(line2) # ============ 操作说明区 ============ hint_label = QLabel( "• 在线自动更新:自动下载并安装新版本\n" "• 稍后更新:保留提示在状态栏,可随时点击更新\n" "• 忽略此版本:本次运行不再提示此版本" ) hint_label.setFont(QFont('Microsoft YaHei', 9)) hint_label.setStyleSheet("color: #666; margin: 5px 0;") layout.addWidget(hint_label) # ============ 按钮区(两行布局)============ # 第一行:主要操作 button_row1 = QHBoxLayout() button_row1.setSpacing(10) self.update_now_btn = QPushButton("🚀 在线自动更新") self.update_now_btn.setFont(QFont('Microsoft YaHei', 11, QFont.Bold)) self.update_now_btn.setMinimumHeight(42) self.update_now_btn.setCursor(QCursor(Qt.PointingHandCursor)) self.update_now_btn.clicked.connect(self.on_update_now) self.update_later_btn = QPushButton("⏰ 稍后更新") self.update_later_btn.setFont(QFont('Microsoft YaHei', 11)) self.update_later_btn.setMinimumHeight(42) self.update_later_btn.setCursor(QCursor(Qt.PointingHandCursor)) self.update_later_btn.clicked.connect(self.on_update_later) button_row1.addWidget(self.update_now_btn) button_row1.addWidget(self.update_later_btn) layout.addLayout(button_row1) # 第二行:次要操作 button_row2 = QHBoxLayout() button_row2.setSpacing(10) self.ignore_btn = QPushButton("🚫 忽略此版本") self.ignore_btn.setFont(QFont('Microsoft YaHei', 10)) self.ignore_btn.setMinimumHeight(38) self.ignore_btn.setCursor(QCursor(Qt.PointingHandCursor)) self.ignore_btn.clicked.connect(self.on_ignore) self.copy_btn = QPushButton("📋 复制下载地址") self.copy_btn.setFont(QFont('Microsoft YaHei', 10)) self.copy_btn.setMinimumHeight(38) self.copy_btn.setCursor(QCursor(Qt.PointingHandCursor)) self.copy_btn.clicked.connect(self.on_copy_url) button_row2.addWidget(self.ignore_btn) button_row2.addWidget(self.copy_btn) layout.addLayout(button_row2) 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 ); } /* 主要操作按钮(立即更新、稍后更新)*/ QPushButton#updateNowBtn { background: qlineargradient( x1:0, y1:0, x2:0, y2:1, stop:0 #4285f4, stop:1 #1565c0 ); border: none; color: white; border-radius: 8px; font-weight: bold; } QPushButton#updateNowBtn:hover { background: qlineargradient( x1:0, y1:0, x2:0, y2:1, stop:0 #5294f5, stop:1 #1e74c1 ); } QPushButton#updateLaterBtn { background: qlineargradient( x1:0, y1:0, x2:0, y2:1, stop:0 #ff9800, stop:1 #f57c00 ); border: none; color: white; border-radius: 8px; } QPushButton#updateLaterBtn:hover { background: qlineargradient( x1:0, y1:0, x2:0, y2:1, stop:0 #ffa726, stop:1 #fb8c00 ); } /* 次要操作按钮(忽略、复制)*/ QPushButton { background: qlineargradient( x1:0, y1:0, x2:0, y2:1, stop:0 #f5f5f5, stop:1 #e0e0e0 ); border: 2px solid #ccc; border-radius: 8px; color: #555; } QPushButton:hover { background: qlineargradient( x1:0, y1:0, x2:0, y2:1, stop:0 #e8e8e8, stop:1 #d0d0d0 ); border: 2px solid #999; } """) # 设置按钮对象名以应用特定样式 self.update_now_btn.setObjectName("updateNowBtn") self.update_later_btn.setObjectName("updateLaterBtn") def on_update_now(self): """立即更新""" self.user_choice = self.CHOICE_UPDATE_NOW self.accept() def on_update_later(self): """稍后更新""" self.user_choice = self.CHOICE_UPDATE_LATER self.accept() def on_ignore(self): """忽略此版本""" self.user_choice = self.CHOICE_IGNORE self.accept() def on_copy_url(self): """复制下载地址""" from PyQt5.QtWidgets import QApplication, QMessageBox clipboard = QApplication.clipboard() clipboard.setText(self.download_url) # 显示复制成功提示(不关闭主对话框) QMessageBox.information( self, "复制成功", f"✅ 下载地址已复制到剪贴板!\n\n" f"您可以直接粘贴(Ctrl+V)到浏览器下载。", QMessageBox.Ok ) def get_user_choice(self): """获取用户选择""" return self.user_choice if __name__ == "__main__": # 测试对话框 import sys from PyQt5.QtWidgets import QApplication app = QApplication(sys.argv) print("=" * 60) print("测试更新对话框") print("=" * 60) print("\n场景1:有更新内容") dialog = UpdateNotificationDialog( version="1.5.64", download_url="https://shuidrop-chat-server.ks3-cn-guangzhou.ksyuncs.com/installers/ShuiDi_AI_Assistant_Setup_v1.5.64.exe", update_content="• 修复了DY图片/视频上传问题\n• 优化了自动更新流程\n• 添加了圆形进度条" ) dialog.exec_() choice = dialog.get_user_choice() if choice == UpdateNotificationDialog.CHOICE_UPDATE_NOW: print("\n用户选择:在线自动更新") elif choice == UpdateNotificationDialog.CHOICE_UPDATE_LATER: print("\n用户选择:稍后更新") elif choice == UpdateNotificationDialog.CHOICE_IGNORE: print("\n用户选择:忽略此版本") else: print("\n用户关闭了对话框") # 测试场景2:无更新内容 print("\n" + "=" * 60) print("场景2:无更新内容(应该隐藏更新内容区域)") print("=" * 60) dialog2 = UpdateNotificationDialog( version="1.5.65", download_url="https://shuidrop-chat-server.ks3-cn-guangzhou.ksyuncs.com/installers/ShuiDi_AI_Assistant_Setup_v1.5.65.exe", update_content="" # 空内容 ) dialog2.exec_() print("\n测试完成!") sys.exit(0)