QStackedWidget添加切换动画后最小化窗口控件位置异常问题求助
问题原因
这个控件偏移问题是Qt的QGraphicsEffect系列类的已知兼容性问题,触发原因有三个:
- 动画结束后
QGraphicsOpacityEffect没有被及时清理,仍然挂载在子控件上,窗口最小化恢复触发重绘时,effect的缓存坐标计算错误 - 父控件
ui.bg_app已经设置了QGraphicsDropShadowEffect,多层控件叠加使用图形效果时,Qt的渲染逻辑容易出现坐标偏差 - 无边框+透明背景的窗口本身重绘逻辑和普通窗口不同,更容易触发图形效果的缓存异常
修复方案
方案1:直接修改现有动画逻辑(改动最小)
动画结束后主动清理挂载在控件上的透明度效果,避免残留影响后续重绘,修改后的淡入代码如下:
QGraphicsOpacityEffect* eff = new QGraphicsOpacityEffect(this); ui.checking->setGraphicsEffect(eff); QPropertyAnimation* a = new QPropertyAnimation(eff, "opacity"); a->setDuration(350); a->setStartValue(0); a->setEndValue(1); a->setEasingCurve(QEasingCurve::InBack); // 新增:动画结束后清除控件效果并释放内存 connect(a, &QPropertyAnimation::finished, this, [=](){ ui.checking->setGraphicsEffect(nullptr); eff->deleteLater(); }); a->start(QPropertyAnimation::DeleteWhenStopped);
淡出代码也做相同的修改,在动画结束的槽函数中清理对应控件的effect即可。
如果修改后仍偶现偏移,可以在CustomMainWindow中重写changeEvent,窗口从最小化恢复时强制刷新子控件:
// CustomMainWindow.h中添加声明 protected: void changeEvent(QEvent *e) override; // CustomMainWindow.cpp中实现 void CustomMainWindow::changeEvent(QEvent *e) { QMainWindow::changeEvent(e); if (e->type() == QEvent::WindowStateChange && !isMinimized()) { ui.stackedWidget->currentWidget()->update(); ui.stackedWidget->adjustSize(); } }
方案2:使用快照实现切换动画(兼容性最好,无偏移风险)
如果需要做QStackedWidget的页面切换动画,更稳妥的方式是不对子控件本身加效果,而是抓取页面快照用临时控件做动画,完全避开图形效果的兼容性问题,实现代码如下:
// 调用该方法切换stackedWidget页面即可自带淡入淡出效果 void Test::switchStackPage(int targetIndex) { if (targetIndex == ui.stackedWidget->currentIndex()) return; // 抓取当前页和目标页的快照 QPixmap currentPix = ui.stackedWidget->currentWidget()->grab(); // 创建临时动画层覆盖在stackedWidget上方 QLabel *animateLayer = new QLabel(this); animateLayer->resize(ui.stackedWidget->size()); animateLayer->move(ui.stackedWidget->pos()); animateLayer->setPixmap(currentPix); animateLayer->show(); animateLayer->raise(); // 直接切换页面,此时被临时层遮挡用户不可见 ui.stackedWidget->setCurrentIndex(targetIndex); // 给临时层加淡出动画 QGraphicsOpacityEffect *eff = new QGraphicsOpacityEffect(animateLayer); animateLayer->setGraphicsEffect(eff); QPropertyAnimation *ani = new QPropertyAnimation(eff, "opacity"); ani->setDuration(350); ani->setStartValue(1); ani->setEndValue(0); ani->setEasingCurve(QEasingCurve::InOutQuad); connect(ani, &QPropertyAnimation::finished, this, [=](){ animateLayer->deleteLater(); eff->deleteLater(); }); ani->start(QPropertyAnimation::DeleteWhenStopped); }
内容的提问来源于stack exchange,提问作者sanab3343
相关产品推荐
相关产品推荐

