PySide6如何等待动画播放完成后再切换QStackedWidget页面
PySide6 中 QStackedWidget 切换时淡出动画失效修复方案
问题原因
setCurrentIndex调用后会在当前事件循环周期内立即完成页面隐藏与切换,不会等待200ms的淡出动画播放完成,因此直接调用时动画还没来得及渲染就已经切到下一页。
time.sleep方案不可行:Qt所有UI绘制、动画帧更新都依赖主线程事件循环,sleep会直接阻塞事件循环,导致界面卡死、动画帧无法刷新- 子线程执行切换方案不可行:Qt所有UI控件操作都必须在主线程执行,跨线程操作UI属于未定义行为,轻则逻辑失效重则程序崩溃
正确实现逻辑
核心思路是等淡出动画完全播放结束后,再触发页面切换操作,通过动画的finished信号回调执行切换逻辑,完全不阻塞主线程。
另外需要注意:QGraphicsOpacityEffect、QPropertyAnimation、QParallelAnimationGroup对象不能写成函数内的局部变量,否则会被Python垃圾回收机制提前回收,导致动画异常中断。
修正后可直接复用的代码
def transition_to_target_page(self, target_page_index: int): # 初始化当前页控件的透明度效果,绑定为实例属性避免被垃圾回收 self.title_opacity_effect = QGraphicsOpacityEffect(self.title) self.btn_opacity_effect = QGraphicsOpacityEffect(self.reminder_btn) self.title.setGraphicsEffect(self.title_opacity_effect) self.reminder_btn.setGraphicsEffect(self.btn_opacity_effect) # 初始化两个控件的淡出动画 self.title_fade_out = QPropertyAnimation(self.title_opacity_effect, b"opacity") self.btn_fade_out = QPropertyAnimation(self.btn_opacity_effect, b"opacity") # 统一配置动画参数,从完全不透明淡出到全透明,时长200ms for anim in [self.title_fade_out, self.btn_fade_out]: anim.setStartValue(1) anim.setEndValue(0) anim.setDuration(200) # 配置并行动画组 self.fade_out_anim_group = QParallelAnimationGroup() self.fade_out_anim_group.addAnimation(self.title_fade_out) self.fade_out_anim_group.addAnimation(self.btn_fade_out) # 绑定动画完成回调:淡出结束后再执行页面切换 self.fade_out_anim_group.finished.connect(lambda: self._execute_page_switch(target_page_index)) self.fade_out_anim_group.start() def _execute_page_switch(self, target_index: int): # 执行实际的页面切换 self.stacked_widget.setCurrentIndex(target_index) # 可选:给新页面增加淡入效果,过渡更自然 new_page = self.stacked_widget.currentWidget() self.page_fade_in_effect = QGraphicsOpacityEffect(new_page) new_page.setGraphicsEffect(self.page_fade_in_effect) self.page_fade_in_anim = QPropertyAnimation(self.page_fade_in_effect, b"opacity") self.page_fade_in_anim.setStartValue(0) self.page_fade_in_anim.setEndValue(1) self.page_fade_in_anim.setDuration(200) self.page_fade_in_anim.start()
额外注意事项
- 触发页面切换时,不要直接调用
setCurrentIndex,而是调用transition_to_target_page(目标页索引)走带动画的切换流程 - 如果需要实现整页的淡出淡入,不需要给页内每个控件单独加透明度效果,直接给整个页面widget加
QGraphicsOpacityEffect做动画即可,代码更简洁 - 如果需要实现滑动、缩放等更复杂的过渡效果,可以基于同样的信号回调逻辑扩展,不要在动画播放过程中直接执行页面切换操作
内容的提问来源于stack exchange,提问作者Omar Yacop
相关产品推荐
相关产品推荐

