如何修复PyQt5启动屏(Splash Screen)实现中的异常问题?
PyQt5启动屏双进度条问题修复
需求背景
开发项目时需实现带GIF的PyQt5启动屏,包含两个进度条:
- 单个菜单加载进度条:跟踪当前菜单加载进度,菜单加载完成后延迟清零
- 整体加载进度条:显示全部菜单加载的整体进度,启动屏需在整体进度到100%后关闭
当前存在的问题
- 整体进度条在加载完第一个菜单后停留在33%,后续菜单加载时不再更新
- 第三个菜单加载时,单菜单进度条仅到78%,启动屏就提前关闭了
原代码
import sys import time from PyQt5.QtWidgets import QApplication, QWidget, QDialog, QProgressBar, QMainWindow, QVBoxLayout from PyQt5.QtCore import Qt, QTimer, QEventLoop, QCoreApplication class SplashScreen(QDialog): def __init__(self): super().__init__() self.setWindowTitle('Splash Screen Example') self.setFixedSize(800, 400) self.setWindowFlag(Qt.FramelessWindowHint) self.setWindowFlag(Qt.WindowStaysOnTopHint) self.initUI() def initUI(self): layout = QVBoxLayout(self) self.progressBarMenu = QProgressBar() self.progressBarProcess = QProgressBar() layout.addWidget(self.progressBarMenu) layout.addWidget(self.progressBarProcess) self.setStyleSheet(''' QProgressBar { background-color: #DA7B93; color: rgb(200, 200, 200); border-style: none; border-radius: 10px; text-align: center; font-size: 20px; } QProgressBar::chunk { border-radius: 10px; background-color: qlineargradient(spread:pad x1:0, x2:1, y1:0.511364, y2:0.523, stop:0 #1C3334, stop:1 #376E6F); } ''') class MyApp(QMainWindow): def __init__(self): super().__init__() self.valueMenu = 0 self.valueProcess = 0 self.window_width, self.window_height = 800, 600 self.setMinimumSize(self.window_width, self.window_height) self.splash_screen = SplashScreen() self.setCentralWidget(self.splash_screen) self.menu_count = 3 self.current_menu = 1 self.timerMenu = QTimer() self.timerMenu.timeout.connect(self.load_next_menu) self.timerMenu.start(1000) self.timerProcess = QTimer() self.timerProcess.timeout.connect(self.update_process_bar) self.timerProcess.start(1000) self.start_time = time.time() self.estimated_time = 10 # Estimated time in seconds for each menu self.remaining_time = self.estimated_time self.overall_progress = 0 self.is_menu_loaded = False def load_next_menu(self): self.valueMenu = 0 if self.current_menu == 1: self.load_menu_one() elif self.current_menu == 2: self.load_menu_two() elif self.current_menu == 3: self.load_menu_three() self.update_menu_progress(self.valueMenu) self.current_menu += 1 if self.current_menu > self.menu_count: self.timerMenu.stop() self.update_menu_progress(100) self.is_menu_loaded = True def load_menu_one(self): menu_one_items = 10 # Number of items in menu one for i in range(menu_one_items): time.sleep(0.5) self.valueMenu += int(100 / menu_one_items) self.update_menu_progress(self.valueMenu) QCoreApplication.processEvents() def load_menu_two(self): menu_two_items = 4 # Number of items in menu two for i in range(menu_two_items): time.sleep(0.5) self.valueMenu += int(100 / menu_two_items) self.update_menu_progress(self.valueMenu) QCoreApplication.processEvents() def load_menu_three(self): menu_three_items = 40 # Number of items in menu three for i in range(menu_three_items): time.sleep(0.5) self.valueMenu += int(100 / menu_three_items) self.update_menu_progress(self.valueMenu) QCoreApplication.processEvents() def update_menu_progress(self, value): self.splash_screen.progressBarMenu.setValue(value) def update_process_bar(self): elapsed_time = int(time.time() - self.start_time) self.remaining_time = self.estimated_time - elapsed_time if self.current_menu > self.menu_count: self.overall_progress = 100 else: self.overall_progress = int((self.current_menu - 1) / self.menu_count * 100) if self.remaining_time <= 0: self.remaining_time = 0 self.timerProcess.stop() self.valueProcess = int(self.overall_progress + (self.valueMenu / self.menu_count)) self.splash_screen.progressBarProcess.setValue(self.valueProcess) # print(f"Elapsed Time: {elapsed_time}s") # print(f"Estimated Time: {self.estimated_time}s") # print(f"Remaining Time: {self.remaining_time}s") if self.current_menu > self.menu_count and self.is_menu_loaded: self.timerProcess.stop() self.splash_screen.close() self.show_main_window() def show_main_window(self): pass if __name__ == '__main__': app = QApplication(sys.argv) window = MyApp() window.show() sys.exit(app.exec_())
问题原因及修复方案
问题1:整体进度条不更新
原因:update_process_bar中仅用current_menu-1计算已完成菜单占比,但current_menu仅在整个菜单加载完成后才+1,导致加载后续菜单时整体进度停滞。
修复:
- 整体进度改为:
(已完成菜单数 + 当前菜单进度占比) / 总菜单数 * 100,实时反映加载状态 - 移除错误的
valueProcess叠加逻辑,直接使用修正后的整体进度值
问题2:第三个菜单进度条未到100%就关闭
原因:
- 40个条目用
int(100/40)取整后每次加2,循环39次仅累加78,未到100 - 菜单加载完成后直接触发启动屏关闭,无进度条延迟清零逻辑
修复:
- 单菜单进度改用
(i+1)/条目数*100浮点计算后取整,避免累加误差 - 菜单加载完成后强制设为100%,再用QTimer延迟1秒清零
- 调整启动屏关闭条件,确保整体进度到100%后再关闭
修改后的完整代码
import sys import time from PyQt5.QtWidgets import QApplication, QDialog, QProgressBar, QMainWindow, QVBoxLayout from PyQt5.QtCore import Qt, QTimer, QCoreApplication class SplashScreen(QDialog): def __init__(self): super().__init__() self.setWindowTitle('Splash Screen Example') self.setFixedSize(800, 400) self.setWindowFlag(Qt.FramelessWindowHint) self.setWindowFlag(Qt.WindowStaysOnTopHint) self.initUI() def initUI(self): layout = QVBoxLayout(self) self.progressBarMenu = QProgressBar() self.progressBarProcess = QProgressBar() layout.addWidget(self.progressBarMenu) layout.addWidget(self.progressBarProcess) self.setStyleSheet(''' QProgressBar { background-color: #DA7B93; color: rgb(200, 200, 200); border-style: none; border-radius: 10px; text-align: center; font-size: 20px; } QProgressBar::chunk { border-radius: 10px; background-color: qlineargradient(spread:pad x1:0, x2:1, y1:0.511364, y2:0.523, stop:0 #1C3334, stop:1 #376E6F); } ''') class MyApp(QMainWindow): def __init__(self): super().__init__() self.valueMenu = 0 self.valueProcess = 0 self.window_width, self.window_height = 800, 600 self.setMinimumSize(self.window_width, self.window_height) self.splash_screen = SplashScreen() self.setCentralWidget(self.splash_screen) self.menu_count = 3 self.current_menu = 1 self.all_menus_loaded = False self.menu_reset_timer = QTimer() self.menu_reset_timer.setSingleShot(True) self.menu_reset_timer.timeout.connect(self.reset_menu_progress) self.timerMenu = QTimer() self.timerMenu.timeout.connect(self.load_next_menu) self.timerMenu.start(1000) self.timerProcess = QTimer() self.timerProcess.timeout.connect(self.update_process_bar) self.timerProcess.start(50) # 提高刷新频率,让进度条更流畅 def load_next_menu(self): self.valueMenu = 0 self.menu_reset_timer.stop() if self.current_menu == 1: self.load_menu_one() elif self.current_menu == 2: self.load_menu_two() elif self.current_menu == 3: self.load_menu_three() # 菜单加载完成后强制设为100%,延迟1秒清零 self.update_menu_progress(100) self.menu_reset_timer.start(1000) self.current_menu += 1 if self.current_menu > self.menu_count: self.timerMenu.stop() self.all_menus_loaded = True def load_menu_one(self): menu_one_items = 10 for i in range(menu_one_items): time.sleep(0.5) self.valueMenu = int((i + 1) / menu_one_items * 100) self.update_menu_progress(self.valueMenu) QCoreApplication.processEvents() def load_menu_two(self): menu_two_items = 4 for i in range(menu_two_items): time.sleep(0.5) self.valueMenu = int((i + 1) / menu_two_items * 100) self.update_menu_progress(self.valueMenu) QCoreApplication.processEvents() def load_menu_three(self): menu_three_items = 40 for i in range(menu_three_items): time.sleep(0.5) self.valueMenu = int((i + 1) / menu_three_items * 100) self.update_menu_progress(self.valueMenu) QCoreApplication.processEvents() def update_menu_progress(self, value): self.splash_screen.progressBarMenu.setValue(value) def reset_menu_progress(self): self.valueMenu = 0 self.update_menu_progress(self.valueMenu) def update_process_bar(self): if self.all_menus_loaded: self.valueProcess = 100 else: completed_menus = self.current_menu - 1 current_menu_progress = self.valueMenu / 100 self.valueProcess = int((completed_menus + current_menu_progress) / self.menu_count * 100) self.splash_screen.progressBarProcess.setValue(self.valueProcess) # 整体进度到100%且所有菜单加载完成后,延迟关闭启动屏 if self.all_menus_loaded and self.valueProcess == 100: QTimer.singleShot(500, self.close_splash_and_show_main) def close_splash_and_show_main(self): self.timerProcess.stop() self.splash_screen.close() self.show_main_window() def show_main_window(self): self.setWindowTitle('Main Window') self.show() if __name__ == '__main__': app = QApplication(sys.argv) window = MyApp() window.show() sys.exit(app.exec_())
关键改进点
- 修正整体进度计算逻辑,实时反映当前加载状态
- 单菜单进度改用浮点计算,避免整数累加误差,加载完成后强制设为100%
- 添加单菜单进度条延迟清零功能,符合需求
- 调整启动屏关闭条件,确保整体进度到100%后再关闭,增加短暂延迟提升用户体验
- 提高进度条刷新频率,让动画更流畅
内容的提问来源于stack exchange,提问作者Rithik
相关产品推荐
相关产品推荐

