139 lines
4.1 KiB
Python
139 lines
4.1 KiB
Python
"""
|
|
LoadingModal pour PyQt6 - Modal de chargement avec barre de progression.
|
|
"""
|
|
from PyQt6.QtWidgets import QDialog, QVBoxLayout, QLabel, QProgressBar
|
|
from PyQt6.QtCore import Qt, QTimer
|
|
from PyQt6.QtGui import QFont
|
|
|
|
|
|
class LoadingModal(QDialog):
|
|
"""Modal de chargement avec barre de progression déterminée ou indéterminée."""
|
|
|
|
def __init__(self, parent, title: str = "Loading", message: str = "Please wait...", determinate: bool = False):
|
|
"""
|
|
Créer une modal de chargement.
|
|
|
|
Args:
|
|
parent: Widget parent
|
|
title: Titre
|
|
message: Message de chargement
|
|
determinate: Si True, barre de progression déterminée (0→100). Sinon, indéterminée
|
|
"""
|
|
super().__init__(parent)
|
|
self.setWindowTitle(title)
|
|
self.setModal(False)
|
|
self.setFixedSize(500, 250)
|
|
self.setStyleSheet("""
|
|
QDialog {
|
|
background-color: #212121;
|
|
border-radius: 8px;
|
|
}
|
|
QLabel {
|
|
color: #ffffff;
|
|
}
|
|
""")
|
|
|
|
# Layout
|
|
layout = QVBoxLayout()
|
|
layout.setContentsMargins(30, 30, 30, 30)
|
|
layout.setSpacing(15)
|
|
|
|
# Titre
|
|
title_label = QLabel(title)
|
|
title_font = QFont()
|
|
title_font.setPointSize(16)
|
|
title_font.setBold(True)
|
|
title_label.setFont(title_font)
|
|
layout.addWidget(title_label)
|
|
|
|
# Message
|
|
self._msg_label = QLabel(message)
|
|
msg_font = QFont()
|
|
msg_font.setPointSize(11)
|
|
self._msg_label.setFont(msg_font)
|
|
layout.addWidget(self._msg_label)
|
|
|
|
# Progress bar
|
|
self._progress = QProgressBar()
|
|
self._progress.setStyleSheet("""
|
|
QProgressBar {
|
|
background-color: #3a3a3a;
|
|
border: none;
|
|
border-radius: 5px;
|
|
height: 8px;
|
|
}
|
|
QProgressBar::chunk {
|
|
background-color: #2196F3;
|
|
border-radius: 5px;
|
|
}
|
|
""")
|
|
|
|
if determinate:
|
|
self._progress.setMinimum(0)
|
|
self._progress.setMaximum(100)
|
|
self._progress.setValue(0)
|
|
self._determinate = True
|
|
else:
|
|
self._progress.setMinimum(0)
|
|
self._progress.setMaximum(0)
|
|
self._determinate = False
|
|
self._animation_timer = QTimer()
|
|
self._animation_timer.timeout.connect(self._animate_progress)
|
|
self._animation_timer.start(50)
|
|
|
|
layout.addWidget(self._progress)
|
|
layout.addStretch()
|
|
|
|
self.setLayout(layout)
|
|
|
|
# Centre la modal
|
|
self.move(parent.x() + parent.width() // 2 - 250,
|
|
parent.y() + parent.height() // 2 - 125)
|
|
|
|
def update_message(self, message: str):
|
|
"""Mettre à jour le message."""
|
|
try:
|
|
self._msg_label.setText(message)
|
|
self.repaint()
|
|
except Exception:
|
|
pass
|
|
|
|
def set_progress(self, value: float):
|
|
"""Définir la progression (0.0 à 1.0) si en mode déterminé."""
|
|
try:
|
|
if self._determinate:
|
|
percent = max(0, min(100, int(value * 100)))
|
|
self._progress.setValue(percent)
|
|
self.repaint()
|
|
except Exception:
|
|
pass
|
|
|
|
def _animate_progress(self):
|
|
"""Animation pour la barre indéterminée."""
|
|
try:
|
|
if not self._determinate:
|
|
current = self._progress.value()
|
|
self._progress.setValue((current + 5) % 100)
|
|
except Exception:
|
|
pass
|
|
|
|
def close(self):
|
|
"""Fermer la modal."""
|
|
try:
|
|
if hasattr(self, '_animation_timer'):
|
|
self._animation_timer.stop()
|
|
self.hide()
|
|
self.deleteLater()
|
|
except Exception:
|
|
pass
|
|
|
|
def closeEvent(self, event):
|
|
"""Gérer la fermeture."""
|
|
try:
|
|
if hasattr(self, '_animation_timer'):
|
|
self._animation_timer.stop()
|
|
except Exception:
|
|
pass
|
|
event.accept()
|
|
|