Module QFlow.components.notify
Sub-modules
QFlow.components.notify.notify-
This module defines the Notify class, which represents an on-screen notification in a PyQt-PySide application …
QFlow.components.notify.properties-
This file contains the constants and properties for the Notify object in this module …
Classes
class Notify (*args, **kwargs)-
Expand source code
@style(STYLE_PATH, True) class Notify(QWidget): """ Represents an on-screen notification within a parent window. This class allows displaying messages with different notification types (success, error, info) and customizable styles. It also includes a progress bar indicating the notification duration. """ cont = {} """Dictionary tracking the number of notifications per parent window.""" def __init__( self, message: str, duration: int = 3000, delay: int = 0, parent=None, type: str = 'success', color: str = 'black', customIcon: QPixmap = None, notificationsLimit: int = 7, characterLimit: int = 60, position: str = 'top-right', items: List[QWidget] = None, opacity: float = 1.0, animatedEvents: Dict[str, bool] = {}, animationValues: Dict[str, float] = {}, autoShow: bool = True ): """ Initializes a Notify object. Args: message (str): The notification message. duration (int, optional): Duration before the notification disappears (in milliseconds). Default is 3000ms. delay (int, optional): Delay before showing the notification (in milliseconds). Default is 0ms. parent (QWidget, optional): The parent widget where the notification will be displayed. It's usually the window. type (str, optional): The type of notification ('success', 'error', 'info'). Default is 'success'. color (str, optional): The theme color ('black' or 'white'). Default is 'black'. customIcon (QPixmap, optional): A custom icon to use instead of the default. notificationsLimit (int, optional): Parent notification limiter. Default is 7. characterLimit (int, optional): Character limit in the notification. Default is 60. position (str, optional): Position of the notification ('top-right', 'top-left', 'bottom-right', 'bottom-left'). Default is 'top-right'. items (List[QWidget], optional): Widgets to add to the notification. Default is None. opacity: (float, optional): The opacity of the notify. animatedEvents: (Dict[str, bool], optional): Default animations for events to {'fadeIn': True, 'fadeOut': True}. animationValues: (Dict[str, bool], optional): Default values for animations {'opacityIncreasedIn': 0.05, 'opacityReductionOut': 0.05}. autoShow: (bool, optional): Whether to show the notification automatically after creation. Default is True. """ super().__init__(parent) self.parent = parent self.duration = duration self.delay = delay self.elapsedTime = 0 self.message = message self.position = position self.items = items self.opacity = opacity self.msRenderTime = 16 self.isVisible = False self.isShown = False self.autoShow = autoShow self.notificationsLimit = notificationsLimit self._animationValues = { 'opacityIncreasedIn': 0.05, 'opacityReductionOut': 0.05 } self._animationValues.update(animationValues) self._animatedEvents = { 'fadeIn': True, 'fadeOut': True } self._animatedEvents.update(animatedEvents) if len(message) > characterLimit: self.message = message[:characterLimit - 1] + '...' self.setWindowFlags(Qt.WindowType.FramelessWindowHint | Qt.WindowType.Tool) self.setAttribute(Qt.WidgetAttribute.WA_TranslucentBackground) self.container = QFrame(self) self.container.setMinimumWidth(270) self.container.setMaximumWidth(self.parent.width()) if color in STYLE_THEME_COLOR: self.containerStyle = STYLE_THEME_COLOR[color]['QFrame'] else: raise KeyError(f"The color does not exist in Notify: '{color}'") self.container.setObjectName(self.containerStyle) self.iconLabel = QLabel(self.container) if type in ICONS: self.icon = ICONS[type]() if customIcon is not None: self.icon = customIcon self.iconLabel.setPixmap(self.icon) self.messageLabel = QLabel(self.message, self.container) if color in STYLE_THEME_COLOR: self.messageLabel.setObjectName(STYLE_THEME_COLOR[color]['QLabel']) else: raise KeyError(f"The color does not exist in Notify: '{color}'") self.progressBar = QProgressBar(self.container) if type in STYLE_BAR: self.progressBarStyle = STYLE_BAR[type] else: raise KeyError(f"The type does not exist in Notify: '{type}'") self.progressBar.setObjectName(self.progressBarStyle) self.progressBar.setFixedHeight(10) self.progressBar.setTextVisible(False) self.progressBar.setMaximum(self.duration) self.progressBar.setValue(0) self.contentLayout = QHBoxLayout() self.contentLayout.setContentsMargins(0, 0, 0, 0) self.contentLayout.setSpacing(8) self.contentLayout.addWidget(self.iconLabel, 0, Qt.AlignmentFlag.AlignVCenter) self.contentLayout.addWidget(self.messageLabel, 1, Qt.AlignmentFlag.AlignVCenter) self.containerLayout = QVBoxLayout(self.container) self.containerLayout.addLayout(self.contentLayout) self.containerLayout.addWidget(self.progressBar) if self.items is not None: for widget in items: if isinstance(widget, QWidget): self.containerLayout.addWidget(widget) self.containerLayout.setContentsMargins(20, 10, 20, 10) self.container.setLayout(self.containerLayout) self.container.adjustSize() # Check notification limit before incrementing counter if self.parent in Notify.cont: if Notify.cont[self.parent] >= notificationsLimit: self.limitExceeded = True return # Don't create notification if limit exceeded else: Notify.cont[self.parent] = 0 self.limitExceeded = False self.mainLayout = QVBoxLayout(self) self.mainLayout.addWidget(self.container) self.mainLayout.setContentsMargins(0, 0, 0, 0) self.setLayout(self.mainLayout) self.adjustSize() # Initialize timers but don't start them yet self.positionTimer = QTimer(self) self.positionTimer.timeout.connect(self.updatePosition) self.timer = QTimer(self) self.timer.timeout.connect(self.updateProgress) # Handle auto-show behavior if self.autoShow: self.show() def show(self) -> None: """Shows the notification. Can be called manually to control when the notification appears.""" if self.isShown or self.limitExceeded: return # Don't show if already shown or limit exceeded self.isShown = True # Handle delay if self.delay > 0: # Schedule the notification to show after delay QTimer.singleShot(self.delay, self._showNotification) else: # Show immediately if no delay self._showNotification() def _showNotification(self) -> None: """Shows the notification after the delay period.""" # Increment counter only when actually showing Notify.cont[self.parent] += 1 self.notificationCount = Notify.cont[self.parent] self.updatePosition() # Start timers self.positionTimer.start(self.msRenderTime) # Approximately 60 fps self.timer.start(self.msRenderTime) # Approximately 60 fps # Schedule auto-close QTimer.singleShot(self.duration, self.close) # Set opacity if self.opacity != 1.0: self.setWindowOpacity(self.opacity) # Handle fade-in animation if self._animatedEvents['fadeIn']: self._animateFadeIn() # Mark as visible and show self.isVisible = True super().show() # Call the parent's show method def _animateFadeOut(self) -> None: timer = QTimer(self) opacity = self.windowOpacity() def _modifyOpacity(): nonlocal opacity opacity -= self._animationValues['opacityReductionOut'] if opacity <= 0.1: timer.stop() self.setWindowOpacity(opacity) timer.timeout.connect(_modifyOpacity) timer.start(self.msRenderTime) def _animateFadeIn(self) -> None: self.setWindowOpacity(0.1) timer = QTimer(self) opacity = self.windowOpacity() def _modifyOpacity(): nonlocal opacity opacity += self._animationValues['opacityIncreasedIn'] if opacity >= self.opacity: timer.stop() self.setWindowOpacity(opacity) timer.timeout.connect(_modifyOpacity) timer.start(self.msRenderTime) def updatePosition(self) -> None: """Updates the notification's position relative to its parent window based on the specified position.""" if self.parent: if not self.parent.isVisible(): self.close() margin = 20 betweenMargin = 20 notificationHeight = self.height() + betweenMargin if 'right' in self.position: x = self.parent.x() + self.parent.width() - self.width() - margin else: x = self.parent.x() + margin if 'top' in self.position: y = self.parent.y() + 40 + (self.notificationCount - 1) * notificationHeight else: y = (self.parent.y() + self.parent.height() - self.notificationCount * notificationHeight) self.move(x, y) def updateProgress(self) -> None: """Updates the progress bar and closes the notification when the duration ends.""" self.elapsedTime += 30 self.progressBar.setValue(self.elapsedTime) if self.elapsedTime >= self.duration: self.timer.stop() if self._animatedEvents['fadeOut']: self._animateFadeOut() QTimer.singleShot(200, self.close) else: self.close() def hide(self) -> None: """Hides the notification without closing it.""" if self.isVisible: super().hide() self.isVisible = False if self.positionTimer.isActive(): self.positionTimer.stop() if self.timer.isActive(): self.timer.stop() def isNotificationVisible(self) -> bool: """Returns True if the notification is currently visible.""" return self.isVisible def isNotificationShown(self) -> bool: """Returns True if show() has been called on this notification.""" return self.isShown def close(self) -> None: """Closes the notification and updates the notification count.""" if self.isVisible and self.parent in Notify.cont and Notify.cont[self.parent] > 0: Notify.cont[self.parent] -= 1 super().close()Represents an on-screen notification within a parent window.
This class allows displaying messages with different notification types (success, error, info) and customizable styles. It also includes a progress bar indicating the notification duration.
Initializes the decorated class and applies the stylesheet.
Args
*args- Positional arguments passed to the original class initializer.
**kwargs- Keyword arguments passed to the original class initializer.
Ancestors
- PyQt6.QtWidgets.QWidget
- PyQt6.QtCore.QObject
- PyQt6.sip.wrapper
- PyQt6.QtGui.QPaintDevice
- PyQt6.sip.simplewrapper
Class variables
var cont-
Dictionary tracking the number of notifications per parent window.
Methods
def close(self) ‑> None-
Expand source code
def close(self) -> None: """Closes the notification and updates the notification count.""" if self.isVisible and self.parent in Notify.cont and Notify.cont[self.parent] > 0: Notify.cont[self.parent] -= 1 super().close()Closes the notification and updates the notification count.
def hide(self) ‑> None-
Expand source code
def hide(self) -> None: """Hides the notification without closing it.""" if self.isVisible: super().hide() self.isVisible = False if self.positionTimer.isActive(): self.positionTimer.stop() if self.timer.isActive(): self.timer.stop()Hides the notification without closing it.
def isNotificationShown(self) ‑> bool-
Expand source code
def isNotificationShown(self) -> bool: """Returns True if show() has been called on this notification.""" return self.isShownReturns True if show() has been called on this notification.
def isNotificationVisible(self) ‑> bool-
Expand source code
def isNotificationVisible(self) -> bool: """Returns True if the notification is currently visible.""" return self.isVisibleReturns True if the notification is currently visible.
def show(self) ‑> None-
Expand source code
def show(self) -> None: """Shows the notification. Can be called manually to control when the notification appears.""" if self.isShown or self.limitExceeded: return # Don't show if already shown or limit exceeded self.isShown = True # Handle delay if self.delay > 0: # Schedule the notification to show after delay QTimer.singleShot(self.delay, self._showNotification) else: # Show immediately if no delay self._showNotification()Shows the notification. Can be called manually to control when the notification appears.
def updatePosition(self) ‑> None-
Expand source code
def updatePosition(self) -> None: """Updates the notification's position relative to its parent window based on the specified position.""" if self.parent: if not self.parent.isVisible(): self.close() margin = 20 betweenMargin = 20 notificationHeight = self.height() + betweenMargin if 'right' in self.position: x = self.parent.x() + self.parent.width() - self.width() - margin else: x = self.parent.x() + margin if 'top' in self.position: y = self.parent.y() + 40 + (self.notificationCount - 1) * notificationHeight else: y = (self.parent.y() + self.parent.height() - self.notificationCount * notificationHeight) self.move(x, y)Updates the notification's position relative to its parent window based on the specified position.
def updateProgress(self) ‑> None-
Expand source code
def updateProgress(self) -> None: """Updates the progress bar and closes the notification when the duration ends.""" self.elapsedTime += 30 self.progressBar.setValue(self.elapsedTime) if self.elapsedTime >= self.duration: self.timer.stop() if self._animatedEvents['fadeOut']: self._animateFadeOut() QTimer.singleShot(200, self.close) else: self.close()Updates the progress bar and closes the notification when the duration ends.