""" Moderne, schöne MessageBox als Alternative zu den hässlichen Qt Standard-Dialogen """ from PyQt5.QtWidgets import (QDialog, QVBoxLayout, QHBoxLayout, QLabel, QPushButton, QFrame, QGraphicsDropShadowEffect) from PyQt5.QtCore import Qt, QTimer, pyqtSignal from PyQt5.QtGui import QFont, QPixmap, QPainter, QColor, QIcon class ModernMessageBox(QDialog): """Moderne, schöne MessageBox mit glasmorphism Design""" clicked = pyqtSignal(str) # "ok", "cancel", "yes", "no" def __init__(self, parent=None, title="", message="", msg_type="info", buttons=None): super().__init__(parent) self.msg_type = msg_type.lower() self.result_value = None if buttons is None: buttons = ["OK"] self.init_ui(title, message, buttons) self.setup_animations() def init_ui(self, title, message, buttons): """Initialisiert die moderne UI""" # Dialog-Eigenschaften self.setWindowFlags(Qt.Dialog | Qt.FramelessWindowHint) self.setAttribute(Qt.WA_TranslucentBackground, True) self.setModal(True) self.setFixedSize(400, 250) # Hauptlayout main_layout = QVBoxLayout(self) main_layout.setContentsMargins(20, 20, 20, 20) # Container mit Glasmorphism-Effekt self.container = QFrame() self.container.setObjectName("messageContainer") # Schatten-Effekt shadow = QGraphicsDropShadowEffect() shadow.setBlurRadius(30) shadow.setXOffset(0) shadow.setYOffset(10) shadow.setColor(QColor(0, 0, 0, 80)) self.container.setGraphicsEffect(shadow) # Container-Layout container_layout = QVBoxLayout(self.container) container_layout.setSpacing(20) container_layout.setContentsMargins(30, 25, 30, 25) # Header mit Icon und Titel header_layout = QHBoxLayout() # Icon basierend auf Nachrichtentyp icon_label = QLabel() icon_label.setFixedSize(32, 32) icon_label.setAlignment(Qt.AlignCenter) icon_text = self.get_icon_for_type(self.msg_type) icon_label.setText(icon_text) icon_label.setObjectName(f"icon{self.msg_type.title()}") # Titel title_label = QLabel(title) title_label.setObjectName("messageTitle") title_label.setWordWrap(True) header_layout.addWidget(icon_label) header_layout.addWidget(title_label, 1) header_layout.setSpacing(15) # Nachricht message_label = QLabel(message) message_label.setObjectName("messageText") message_label.setWordWrap(True) message_label.setAlignment(Qt.AlignLeft | Qt.AlignTop) # Buttons button_layout = QHBoxLayout() button_layout.addStretch() for i, button_text in enumerate(buttons): btn = QPushButton(button_text) btn.setObjectName("messageButton" if i == 0 else "messageButtonSecondary") btn.setMinimumHeight(35) btn.setMinimumWidth(80) btn.clicked.connect(lambda checked, text=button_text.lower(): self.button_clicked(text)) button_layout.addWidget(btn) if i < len(buttons) - 1: button_layout.addSpacing(10) # Layout zusammenfügen container_layout.addLayout(header_layout) container_layout.addWidget(message_label, 1) container_layout.addLayout(button_layout) main_layout.addWidget(self.container) # Stil anwenden self.apply_styles() def get_icon_for_type(self, msg_type): """Gibt das passende Icon für den Nachrichtentyp zurück""" icons = { "info": "ℹ️", "success": "✅", "warning": "⚠️", "error": "❌", "critical": "🚨", "question": "❓" } return icons.get(msg_type, "ℹ️") def apply_styles(self): """Wendet die modernen Styles an""" # Farben basierend auf Typ colors = { "info": { "bg": "rgba(59, 130, 246, 0.1)", "border": "rgba(59, 130, 246, 0.3)", "accent": "#3B82F6" }, "success": { "bg": "rgba(34, 197, 94, 0.1)", "border": "rgba(34, 197, 94, 0.3)", "accent": "#22C55E" }, "warning": { "bg": "rgba(245, 158, 11, 0.1)", "border": "rgba(245, 158, 11, 0.3)", "accent": "#F59E0B" }, "error": { "bg": "rgba(239, 68, 68, 0.1)", "border": "rgba(239, 68, 68, 0.3)", "accent": "#EF4444" }, "critical": { "bg": "rgba(220, 38, 38, 0.1)", "border": "rgba(220, 38, 38, 0.3)", "accent": "#DC2626" }, "question": { "bg": "rgba(168, 85, 247, 0.1)", "border": "rgba(168, 85, 247, 0.3)", "accent": "#A855F7" } } color_scheme = colors.get(self.msg_type, colors["info"]) style = f""" QDialog {{ background: transparent; }} #messageContainer {{ background: qlineargradient(x1:0, y1:0, x2:0, y2:1, stop:0 rgba(255, 255, 255, 0.95), stop:1 rgba(248, 250, 252, 0.95)); border: 1px solid {color_scheme['border']}; border-radius: 16px; backdrop-filter: blur(10px); }} #messageTitle {{ font-family: 'Segoe UI', Arial, sans-serif; font-size: 16px; font-weight: 600; color: #1e293b; margin: 0; }} #messageText {{ font-family: 'Segoe UI', Arial, sans-serif; font-size: 14px; color: #475569; line-height: 1.5; }} #icon{self.msg_type.title()} {{ font-size: 24px; background: {color_scheme['bg']}; border: 1px solid {color_scheme['border']}; border-radius: 16px; padding: 4px; }} #messageButton {{ background: qlineargradient(x1:0, y1:0, x2:0, y2:1, stop:0 {color_scheme['accent']}, stop:1 {color_scheme['accent']}); color: white; border: none; border-radius: 8px; font-family: 'Segoe UI', Arial, sans-serif; font-size: 13px; font-weight: 500; padding: 8px 16px; }} #messageButton:hover {{ background: qlineargradient(x1:0, y1:0, x2:0, y2:1, stop:0 {color_scheme['accent']}, stop:1 {color_scheme['accent']}); transform: translateY(-1px); }} #messageButton:pressed {{ transform: translateY(0px); }} #messageButtonSecondary {{ background: rgba(148, 163, 184, 0.1); color: #64748b; border: 1px solid rgba(148, 163, 184, 0.3); border-radius: 8px; font-family: 'Segoe UI', Arial, sans-serif; font-size: 13px; font-weight: 500; padding: 8px 16px; }} #messageButtonSecondary:hover {{ background: rgba(148, 163, 184, 0.2); border-color: rgba(148, 163, 184, 0.5); }} """ self.setStyleSheet(style) def setup_animations(self): """Setzt Animationen ein""" # Sanftes Einblenden self.setWindowOpacity(0) self.fade_timer = QTimer() self.fade_timer.timeout.connect(self.fade_in) self.opacity = 0 self.fade_timer.start(16) # ~60 FPS def fade_in(self): """Fade-in Animation""" self.opacity += 0.1 if self.opacity >= 1: self.opacity = 1 self.fade_timer.stop() self.setWindowOpacity(self.opacity) def button_clicked(self, button_text): """Behandelt Button-Clicks""" self.result_value = button_text self.clicked.emit(button_text) self.accept() def mousePressEvent(self, event): """Ermöglicht das Verschieben des Dialogs""" if event.button() == Qt.LeftButton: self.drag_position = event.globalPos() - self.frameGeometry().topLeft() event.accept() def mouseMoveEvent(self, event): """Verschiebt den Dialog""" if event.buttons() == Qt.LeftButton and hasattr(self, 'drag_position'): self.move(event.globalPos() - self.drag_position) event.accept() # Convenience-Funktionen für einfache Nutzung def show_info(parent=None, title="Information", message="", buttons=None): """Zeigt eine moderne Info-MessageBox""" if buttons is None: buttons = ["OK"] dialog = ModernMessageBox(parent, title, message, "info", buttons) return dialog.exec_() def show_success(parent=None, title="Erfolg", message="", buttons=None): """Zeigt eine moderne Erfolg-MessageBox""" if buttons is None: buttons = ["OK"] dialog = ModernMessageBox(parent, title, message, "success", buttons) return dialog.exec_() def show_warning(parent=None, title="Warnung", message="", buttons=None): """Zeigt eine moderne Warnung-MessageBox""" if buttons is None: buttons = ["OK"] dialog = ModernMessageBox(parent, title, message, "warning", buttons) return dialog.exec_() def show_error(parent=None, title="Fehler", message="", buttons=None): """Zeigt eine moderne Fehler-MessageBox""" if buttons is None: buttons = ["OK"] dialog = ModernMessageBox(parent, title, message, "error", buttons) return dialog.exec_() def show_critical(parent=None, title="Kritischer Fehler", message="", buttons=None): """Zeigt eine moderne kritische Fehler-MessageBox""" if buttons is None: buttons = ["OK"] dialog = ModernMessageBox(parent, title, message, "critical", buttons) return dialog.exec_() def show_question(parent=None, title="Frage", message="", buttons=None): """Zeigt eine moderne Frage-MessageBox""" if buttons is None: buttons = ["Ja", "Nein"] dialog = ModernMessageBox(parent, title, message, "question", buttons) return dialog.exec_()