Dieser Commit ist enthalten in:
Claude Project Manager
2025-08-01 23:50:28 +02:00
Commit 04585e95b6
290 geänderte Dateien mit 64086 neuen und 0 gelöschten Zeilen

Datei anzeigen

@ -0,0 +1,316 @@
"""
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_()