I'm starting to build a UI with PyQt5. For now, I have a mainwindow in which I put a QStackedWidget. It only contains 2 widgets currently (**welcome_widget **which is the first widget that the user would see after opening the UI / main_widget which is the widget the user would arrive on after having successfully entered its idents).
I would like that, after successfully enter idents (button in welcome_widget, not shown here, no security on it for the moment), the welcome_widget go off with and animation (vertically above the window) and the main_widget arrive with an animation too (vertically from below the window). It works well for the welcome_widget (function "enter_the_app"). For the main_widget (function 'show_main_widget' and 'set_main_widget_visible') it works, but the widget quick pop one time before it reappears with the animation.
import sys
from PyQt5.QtWidgets import QApplication, QWidget, QFrame, QLabel, QVBoxLayout, QHBoxLayout, QPushButton, QSizePolicy, \
QMainWindow, QLineEdit, QStackedWidget, QGraphicsOpacityEffect, QScrollArea, QGridLayout, QAction
from PyQt5.QtCore import Qt, QPropertyAnimation, QEasingCurve, QPoint, QSize, QSequentialAnimationGroup, \
QParallelAnimationGroup, QRect
from PyQt5.QtGui import QPixmap, QIcon, QPalette, QBrush, QPainter, QPainterPath
class MainWindow(QMainWindow):
"""
"""
def __init__(self):
super().__init__()
self.background_widget = BackgroundWidget("lightgreen") # Create the background widget
self.welcome_widget = WelcomeWidgetObj(self) # First widget to be shown opening the ui
self.welcome_anim = QPropertyAnimation(self.welcome_widget, b"geometry") # Animation of the disappearing of welcome_widget
self.main_widget = MainWidget(self) # First widget to appear after having successfully enter idents
self.stacked_widget = QStackedWidget() # Will contain the different pages of the ui
self.stacked_widget.addWidget(self.welcome_widget) # Add welcome_widget page to the stacked widget
self.stacked_widget.addWidget(self.main_widget) # Add main_widget page to the stacked widget
self.init_ui()
self.center()
def init_ui(self):
"""
Initialize main window.
:return: None
"""
self.setCentralWidget(self.background_widget) # To have a background image that takes all the space provided by the mainwindow
background_widget_layout = QVBoxLayout(self.background_widget)
background_widget_layout.addWidget(self.stacked_widget) # Add the stacked widget that contains all the pages of the ui, in 'background_widget'
# This means that if the pages don't have background, it will be the same as 'background_widget'
self.setWindowIcon(QIcon('')) # UI's logo
self.setWindowTitle('.....') # UI's name
self.setGeometry(100, 100, 1400, 850) # (x, y, width, height) -> initial main window's size
def center(self):
"""
This function lets display the window in center of the screen.
:return: None
"""
# Get the screen geometry
screen = QApplication.primaryScreen()
screen_geometry = screen.geometry()
# Get the center point of the screen
center_point = screen_geometry.center()
# Calculate the center position for the window
window_geometry = self.frameGeometry()
window_geometry.moveCenter(center_point)
# Move the window to the center position
self.move(window_geometry.topLeft())
def enter_the_app(self):
"""
This function applies an animation on the 'welcome_widget' after the user would have successfully provided its idents
:return: None
"""
self.welcome_anim.setEndValue(QRect(0, -self.height(), self.width(), self.height())) # Indicate where the widget has to end
self.welcome_anim.setDuration(800) # Animation's speed
self.welcome_anim.start() # Start animations
self.welcome_anim.finished.connect(self.show_main_widget) # Connect the end of the animation with the apparition of 'main_widget'
def show_main_widget(self):
"""
This function performs animation on main_widget and then makes it visible.
:return: None
"""
self.stacked_widget.setCurrentWidget(self.main_widget) # Set 'main_widget' as the current widget of 'stacked_widget'
self.main_widget.background_widget.setGeometry(QRect(0, self.height(), self.width(), self.height()))
# self.main_widget.background_widget.show() # Sees show method of 'main_widget'
self.anim_main_widget = QPropertyAnimation(self.main_widget.background_widget, b"geometry") # main_widget appearance animation
self.anim_main_widget.setStartValue(QRect(0, self.height(), self.width(), self.height()))
self.anim_main_widget.setEndValue(QRect(0, 0, self.width(), self.height()))
self.anim_main_widget.setDuration(800)
self.anim_main_widget.start()
class BackgroundWidget(QWidget):
def __init__(self, color, parent=None):
super().__init__(parent)
self.setStyleSheet(f"background-color : {color}")
class WelcomeWidgetObj(QWidget):
"""
Widget corresponding to the welcome page (in which the user will have to enter idents to access the ui).
"""
def __init__(self, parent):
super().__init__(parent)
self.main_layout = QVBoxLayout(self)
self.main_layout.setContentsMargins(0, 0, 0, 0) # First widget inside 'main_layout' will not have margin with it
self.main_layout.setSpacing(0) # No spacing between widgets put inside 'main_layout'
self.init_widget()
def get_main_layout(self):
return self.main_layout
def init_widget(self):
"""
Builds self, first widget seen by the user after opening the ui
:return: None
"""
main_frame = QFrame()
main_frame_layout = QVBoxLayout(main_frame)
main_frame_layout.setAlignment(Qt.AlignCenter)
main_frame_layout.setSpacing(20)
self.get_main_layout().addWidget(main_frame)
enter_app_button = QPushButton("VALIDER")
enter_app_button.setFixedHeight(50)
enter_app_button.setFixedWidth(180)
enter_app_button.setStyleSheet("background-color : purple")
enter_app_button.clicked.connect(self.parent().enter_the_app)
main_frame_layout.addWidget(enter_app_button)
class MainWidget(QWidget):
def __init__(self, parent):
super().__init__(parent)
self.main_layout = QVBoxLayout(self) # Set up the widget's main layout
self.main_layout.setContentsMargins(0, 0, 0, 0) # Widgets inside 'main_layout' will have no margins
self.main_window = parent
self.background_widget = BackgroundWidget("pink")
self.parent_geometry = parent.geometry()
self.init_widget()
def get_main_window(self):
return self.main_window
def get_main_layout(self):
return self.main_layout
def get_background_widget(self):
return self.background_widget
def init_widget(self):
"""
:return:
"""
background_widget_layout = QVBoxLayout(self.get_background_widget())
background_widget_layout.setContentsMargins(40, 20, 40, 20)
self.get_main_layout().addWidget(self.get_background_widget())
# self.get_background_widget().hide() # Initially hide the widget
title_frame = QFrame()
title_frame.setStyleSheet('background-color : red')
background_widget_layout.addWidget(title_frame)
title_frame.setMaximumHeight(110)
title_frame_layout = QHBoxLayout(title_frame)
title_frame_layout.setAlignment(Qt.AlignCenter)
back_home_button = QPushButton("BUTTON 1")
back_home_button.setFixedSize(75, 75)
title_frame_layout.addWidget(back_home_button)
back_home_button.setStyleSheet("background-color : blue")
bottom_frame = QFrame()
bottom_frame.setStyleSheet("background-color : yellow")
background_widget_layout.addWidget(bottom_frame)
if __name__ == '__main__':
# Create the application
app = QApplication(sys.argv)
# Create the main window
window = MainWindow()
# Show the main window
window.show()
# Start the application event loop
sys.exit(app.exec_())
The above example reproduces the problem (mostly if you quickly clik on the button, sometimes later too, I don't really understand when it happens). You can try several times if it doesn't reproduce the problem on first tries.