""" 个人信息卡片模态框 - 头像、微信二维码、邮箱 - 高级UI设计,带装饰元素和动画 """ import os import sys from pathlib import Path from PySide6.QtWidgets import ( QDialog, QVBoxLayout, QHBoxLayout, QLabel, QPushButton, QWidget, QGraphicsOpacityEffect, QApplication ) from PySide6.QtCore import ( Qt, QPropertyAnimation, QEasingCurve, QTimer, QPoint, QRect, QParallelAnimationGroup, Signal ) from PySide6.QtGui import ( QPixmap, QPainter, QColor, QLinearGradient, QRadialGradient, QFont, QPen, QBrush, QPainterPath, QCursor ) import math def get_resource_path(relative_path: str) -> str: """获取资源文件的绝对路径(兼容打包后)""" if getattr(sys, 'frozen', False): # 打包后的路径 base_path = Path(sys._MEIPASS) else: # 开发时的路径 base_path = Path(__file__).parent.parent return str(base_path / relative_path) # 资源路径 AVATAR_PATH = get_resource_path("image/头像.jpg") QRCODE_PATH = get_resource_path("image/二维码.jpg") class FloatingOrb(QWidget): """浮动装饰球""" def __init__(self, size: int, color: QColor, parent=None): super().__init__(parent) self.orb_size = size self.orb_color = color self.setFixedSize(size, size) self.setAttribute(Qt.WidgetAttribute.WA_TransparentForMouseEvents) # 设置透明效果 self.opacity_effect = QGraphicsOpacityEffect(self) self.opacity_effect.setOpacity(0.6) self.setGraphicsEffect(self.opacity_effect) def paintEvent(self, event): painter = QPainter(self) painter.setRenderHint(QPainter.RenderHint.Antialiasing) # 径向渐变 gradient = QRadialGradient( self.orb_size / 2, self.orb_size / 2, self.orb_size / 2 ) gradient.setColorAt(0, QColor(self.orb_color.red(), self.orb_color.green(), self.orb_color.blue(), 120)) gradient.setColorAt(0.5, QColor(self.orb_color.red(), self.orb_color.green(), self.orb_color.blue(), 60)) gradient.setColorAt(1, QColor(self.orb_color.red(), self.orb_color.green(), self.orb_color.blue(), 0)) painter.setBrush(gradient) painter.setPen(Qt.PenStyle.NoPen) painter.drawEllipse(0, 0, self.orb_size, self.orb_size) class GlowButton(QPushButton): """发光按钮""" def __init__(self, text: str, primary: bool = True, parent=None): super().__init__(text, parent) self.primary = primary self._hovered = False self.setFixedHeight(44) self.setCursor(Qt.CursorShape.PointingHandCursor) self.setFont(QFont("Microsoft YaHei UI", 10, QFont.Weight.Medium)) self.setStyleSheet(""" QPushButton { border: none; border-radius: 10px; padding: 10px 24px; color: white; } """) def enterEvent(self, event): self._hovered = True self.update() def leaveEvent(self, event): self._hovered = False self.update() def paintEvent(self, event): painter = QPainter(self) painter.setRenderHint(QPainter.RenderHint.Antialiasing) rect = self.rect() if self.primary: # 主按钮 - 奶酪色渐变 gradient = QLinearGradient(0, 0, rect.width(), 0) if self._hovered: gradient.setColorAt(0, QColor("#fcd34d")) gradient.setColorAt(1, QColor("#f59e0b")) else: gradient.setColorAt(0, QColor("#fbbf24")) gradient.setColorAt(1, QColor("#d97706")) painter.setBrush(gradient) painter.setPen(Qt.PenStyle.NoPen) painter.drawRoundedRect(rect, 10, 10) # 发光效果 if self._hovered: glow = QRadialGradient(rect.center().x(), rect.center().y(), rect.width() / 2) glow.setColorAt(0, QColor(251, 191, 36, 60)) glow.setColorAt(1, QColor(251, 191, 36, 0)) painter.setBrush(glow) painter.drawRoundedRect(rect.adjusted(-5, -5, 5, 5), 15, 15) else: # 次按钮 - 透明边框 if self._hovered: painter.setBrush(QColor(71, 85, 105, 80)) else: painter.setBrush(QColor(71, 85, 105, 40)) painter.setPen(QPen(QColor("#475569"), 1)) painter.drawRoundedRect(rect.adjusted(1, 1, -1, -1), 10, 10) # 绘制文字 painter.setPen(QColor("white") if self.primary else QColor("#94a3b8")) painter.setFont(self.font()) painter.drawText(rect, Qt.AlignmentFlag.AlignCenter, self.text()) class ProfileCard(QDialog): """个人信息卡片模态框""" def __init__(self, parent=None): super().__init__(parent) self.setWindowFlags( Qt.WindowType.FramelessWindowHint | Qt.WindowType.Dialog ) self.setAttribute(Qt.WidgetAttribute.WA_TranslucentBackground) self.setModal(True) self.setFixedSize(480, 780) self._drag_pos = None self.setup_ui() self.setup_animations() self.add_decorations() def setup_ui(self): """设置UI""" # 主容器 self.container = QWidget(self) self.container.setGeometry(0, 0, 480, 780) main_layout = QVBoxLayout(self.container) main_layout.setContentsMargins(0, 0, 0, 0) main_layout.setSpacing(0) # 内容卡片 self.card = QWidget() self.card.setObjectName("profile_card") card_layout = QVBoxLayout(self.card) card_layout.setContentsMargins(32, 24, 32, 24) card_layout.setSpacing(12) # 关闭按钮 close_btn = QPushButton("×") close_btn.setFixedSize(36, 36) close_btn.setCursor(Qt.CursorShape.PointingHandCursor) close_btn.setStyleSheet(""" QPushButton { background: rgba(71, 85, 105, 0.4); border: none; border-radius: 18px; color: #94a3b8; font-size: 20px; font-weight: bold; } QPushButton:hover { background: rgba(239, 68, 68, 0.6); color: white; } """) close_btn.clicked.connect(self.close_with_animation) close_layout = QHBoxLayout() close_layout.addStretch() close_layout.addWidget(close_btn) card_layout.addLayout(close_layout) # 头像区域 avatar_container = QWidget() avatar_container.setFixedHeight(100) avatar_layout = QHBoxLayout(avatar_container) avatar_layout.setAlignment(Qt.AlignmentFlag.AlignCenter) self.avatar_label = QLabel() self.avatar_label.setFixedSize(100, 100) self.avatar_label.setStyleSheet(""" QLabel { border-radius: 50px; border: 3px solid #fbbf24; } """) self._load_avatar() avatar_layout.addWidget(self.avatar_label) card_layout.addWidget(avatar_container) # 名称 name_label = QLabel("奶酪云工具箱") name_label.setAlignment(Qt.AlignmentFlag.AlignCenter) name_label.setStyleSheet(""" QLabel { color: #f8fafc; font-size: 22px; font-weight: bold; font-family: "Microsoft YaHei UI"; } """) card_layout.addWidget(name_label) # 副标题 subtitle_label = QLabel("高效办公 · 精致生活") subtitle_label.setAlignment(Qt.AlignmentFlag.AlignCenter) subtitle_label.setStyleSheet(""" QLabel { color: #64748b; font-size: 13px; font-family: "Microsoft YaHei UI"; } """) card_layout.addWidget(subtitle_label) card_layout.addSpacing(8) # 分割线 divider = QWidget() divider.setFixedHeight(1) divider.setStyleSheet("background: qlineargradient(x1:0, y1:0, x2:1, y2:0, stop:0 transparent, stop:0.5 #334155, stop:1 transparent);") card_layout.addWidget(divider) card_layout.addSpacing(8) # 二维码区域 qr_container = QWidget() qr_layout = QVBoxLayout(qr_container) qr_layout.setAlignment(Qt.AlignmentFlag.AlignCenter) qr_layout.setSpacing(8) qr_title = QLabel("📱 微信扫码添加好友") qr_title.setAlignment(Qt.AlignmentFlag.AlignCenter) qr_title.setStyleSheet(""" QLabel { color: #94a3b8; font-size: 12px; font-family: "Microsoft YaHei UI"; } """) qr_layout.addWidget(qr_title) self.qr_label = QLabel() self.qr_label.setFixedSize(220, 220) self.qr_label.setStyleSheet(""" QLabel { background: white; border-radius: 12px; } """) self._load_qrcode() qr_layout.addWidget(self.qr_label, 0, Qt.AlignmentFlag.AlignCenter) card_layout.addWidget(qr_container) card_layout.addSpacing(10) # 邮箱区域 email_container = QWidget() email_container.setStyleSheet(""" QWidget { background: rgba(30, 41, 59, 0.6); border-radius: 12px; } """) email_layout = QVBoxLayout(email_container) email_layout.setContentsMargins(20, 16, 20, 16) email_layout.setSpacing(8) email_title = QLabel("📧 合作联系邮箱") email_title.setStyleSheet(""" QLabel { color: #94a3b8; font-size: 12px; background: transparent; } """) email_layout.addWidget(email_title) email_row = QHBoxLayout() self.email_label = QLabel("workerqi@163.com") self.email_label.setStyleSheet(""" QLabel { color: #fbbf24; font-size: 16px; font-weight: bold; background: transparent; } """) email_row.addWidget(self.email_label) email_row.addStretch() copy_btn = GlowButton("复制", False) copy_btn.setFixedSize(70, 34) copy_btn.clicked.connect(self.copy_email) email_row.addWidget(copy_btn) send_btn = GlowButton("发送邮件", True) send_btn.setFixedSize(90, 34) send_btn.clicked.connect(self.send_email) email_row.addWidget(send_btn) email_layout.addLayout(email_row) card_layout.addWidget(email_container) card_layout.addStretch() # 底部提示 tip_label = QLabel("点击空白处关闭") tip_label.setAlignment(Qt.AlignmentFlag.AlignCenter) tip_label.setStyleSheet(""" QLabel { color: #475569; font-size: 11px; } """) card_layout.addWidget(tip_label) main_layout.addWidget(self.card) def _load_avatar(self): """加载头像""" if os.path.exists(AVATAR_PATH): pixmap = QPixmap(AVATAR_PATH) if not pixmap.isNull(): # 创建圆形头像 scaled = pixmap.scaled(94, 94, Qt.AspectRatioMode.KeepAspectRatioByExpanding, Qt.TransformationMode.SmoothTransformation) # 裁剪为圆形 rounded = QPixmap(94, 94) rounded.fill(Qt.GlobalColor.transparent) painter = QPainter(rounded) painter.setRenderHint(QPainter.RenderHint.Antialiasing) path = QPainterPath() path.addEllipse(0, 0, 94, 94) painter.setClipPath(path) # 居中裁剪 x = (scaled.width() - 94) // 2 y = (scaled.height() - 94) // 2 painter.drawPixmap(0, 0, scaled, x, y, 94, 94) painter.end() self.avatar_label.setPixmap(rounded) return # 默认头像 self.avatar_label.setText("🧀") self.avatar_label.setStyleSheet(self.avatar_label.styleSheet() + """ font-size: 48px; background: qlineargradient(x1:0, y1:0, x2:1, y2:1, stop:0 #fbbf24, stop:1 #d97706); """) def _load_qrcode(self): """加载二维码""" if os.path.exists(QRCODE_PATH): pixmap = QPixmap(QRCODE_PATH) if not pixmap.isNull(): # 缩放到完整显示,保持宽高比 scaled = pixmap.scaled(210, 210, Qt.AspectRatioMode.KeepAspectRatio, Qt.TransformationMode.SmoothTransformation) self.qr_label.setPixmap(scaled) self.qr_label.setAlignment(Qt.AlignmentFlag.AlignCenter) return self.qr_label.setText("二维码") self.qr_label.setAlignment(Qt.AlignmentFlag.AlignCenter) def add_decorations(self): """添加装饰元素""" # 添加浮动装饰球 orb1 = FloatingOrb(120, QColor("#fbbf24"), self.container) orb1.move(-30, -30) orb2 = FloatingOrb(80, QColor("#3b82f6"), self.container) orb2.move(420, 50) orb3 = FloatingOrb(60, QColor("#8b5cf6"), self.container) orb3.move(400, 500) orb4 = FloatingOrb(100, QColor("#ec4899"), self.container) orb4.move(-20, 480) # 确保装饰在底层 orb1.lower() orb2.lower() orb3.lower() orb4.lower() def setup_animations(self): """设置动画""" # 卡片淡入效果 self.card_opacity = QGraphicsOpacityEffect(self.card) self.card_opacity.setOpacity(0) self.card.setGraphicsEffect(self.card_opacity) self.fade_anim = QPropertyAnimation(self.card_opacity, b"opacity") self.fade_anim.setDuration(300) self.fade_anim.setEasingCurve(QEasingCurve.Type.OutCubic) def showEvent(self, event): super().showEvent(event) # 居中显示 if self.parent(): parent_rect = self.parent().rect() x = (parent_rect.width() - self.width()) // 2 y = (parent_rect.height() - self.height()) // 2 self.move(self.parent().mapToGlobal(QPoint(x, y))) # 播放淡入动画 self.fade_anim.setStartValue(0) self.fade_anim.setEndValue(1) self.fade_anim.start() def close_with_animation(self): """带动画关闭""" self.fade_anim.setStartValue(1) self.fade_anim.setEndValue(0) self.fade_anim.finished.connect(self.accept) self.fade_anim.start() def copy_email(self): """复制邮箱""" clipboard = QApplication.clipboard() clipboard.setText("workerqi@163.com") # 临时显示"已复制" original_text = self.email_label.text() self.email_label.setText("✓ 已复制到剪贴板") self.email_label.setStyleSheet(""" QLabel { color: #22c55e; font-size: 16px; font-weight: bold; background: transparent; } """) QTimer.singleShot(1500, lambda: self._reset_email_label(original_text)) def _reset_email_label(self, text): """重置邮箱标签""" self.email_label.setText(text) self.email_label.setStyleSheet(""" QLabel { color: #fbbf24; font-size: 16px; font-weight: bold; background: transparent; } """) def send_email(self): """发送邮件""" import webbrowser webbrowser.open("mailto:workerqi@163.com?subject=奶酪云工具箱-合作咨询") def paintEvent(self, event): """绘制背景""" painter = QPainter(self) painter.setRenderHint(QPainter.RenderHint.Antialiasing) # 半透明遮罩背景 painter.fillRect(self.rect(), QColor(0, 0, 0, 120)) # 卡片背景 card_rect = self.card.geometry().adjusted(20, 20, -20, -20) # 卡片阴影 shadow_color = QColor(0, 0, 0, 80) for i in range(10): painter.setPen(Qt.PenStyle.NoPen) painter.setBrush(QColor(0, 0, 0, int(80 - i * 8))) painter.drawRoundedRect(card_rect.adjusted(-i*2, -i*2, i*2, i*2), 24 + i, 24 + i) # 卡片主体 - 玻璃质感 gradient = QLinearGradient(card_rect.topLeft(), card_rect.bottomRight()) gradient.setColorAt(0, QColor(30, 41, 59, 240)) gradient.setColorAt(0.5, QColor(15, 23, 42, 250)) gradient.setColorAt(1, QColor(30, 41, 59, 240)) painter.setBrush(gradient) painter.setPen(QPen(QColor(71, 85, 105, 100), 1)) painter.drawRoundedRect(card_rect, 24, 24) # 顶部高光 highlight_rect = QRect(card_rect.x() + 40, card_rect.y(), card_rect.width() - 80, 2) highlight_gradient = QLinearGradient(highlight_rect.topLeft(), highlight_rect.topRight()) highlight_gradient.setColorAt(0, QColor(251, 191, 36, 0)) highlight_gradient.setColorAt(0.5, QColor(251, 191, 36, 150)) highlight_gradient.setColorAt(1, QColor(251, 191, 36, 0)) painter.setBrush(highlight_gradient) painter.setPen(Qt.PenStyle.NoPen) painter.drawRoundedRect(highlight_rect, 1, 1) def mousePressEvent(self, event): """点击空白处关闭""" card_rect = self.card.geometry().adjusted(20, 20, -20, -20) if not card_rect.contains(event.pos()): self.close_with_animation() else: self._drag_pos = event.globalPosition().toPoint() - self.frameGeometry().topLeft() def mouseMoveEvent(self, event): """拖动窗口""" if self._drag_pos: self.move(event.globalPosition().toPoint() - self._drag_pos) def mouseReleaseEvent(self, event): self._drag_pos = None