You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何为QDialog实现缩放动画?现有方案模态问题求解决

QDialog平滑缩放弹出动画实现方案

针对你遇到的QDialog缩放动画无法使用模态exec()的问题,提供两种可行方案:


方案一:修复QGraphicsView的模态问题

如果你想保留QGraphicsView的实现方式,可以通过设置模态属性+事件循环来模拟exec()的效果:

修改后代码

from PyQt6.QtWidgets import (QApplication, QDialog, QStyleFactory, QGraphicsView,
                             QGraphicsScene, QGraphicsProxyWidget)
from PyQt6.QtCore import Qt, QPropertyAnimation, QEasingCurve, QEventLoop
from PyQt6 import uic
import sys
import os


class ExpandingDialog(QDialog):
    def __init__(self):
        super().__init__()
        uic.loadUi("Error.ui", self)
        self.setWindowFlag(Qt.WindowType.FramelessWindowHint)
        self.setAttribute(Qt.WidgetAttribute.WA_TranslucentBackground)
        self.hide()  # 隐藏原Dialog,不直接显示

        # 创建Graphics组件
        self.scene = QGraphicsScene()
        self.view = QGraphicsView(self.scene)
        self.view.setWindowFlags(Qt.WindowType.FramelessWindowHint)
        self.view.setAttribute(Qt.WidgetAttribute.WA_TranslucentBackground)
        self.view.setStyleSheet("background: transparent; border: none;")
        self.view.setFixedSize(self.width(), self.height())
        # 设置view为应用级模态
        self.view.setWindowModality(Qt.WindowModality.ApplicationModal)

        self.proxy_widget = QGraphicsProxyWidget()
        self.proxy_widget.setWidget(self)
        self.scene.addItem(self.proxy_widget)
        # 同步view和原Dialog的关闭状态
        self.view.closeEvent = lambda event: self.close()

    def showEvent(self, event):
        self.start_animation()
        self.view.show()
        # 启动事件循环等待view关闭,实现模态效果
        loop = QEventLoop()
        self.view.destroyed.connect(loop.quit)
        loop.exec()

    def start_animation(self):
        # 缩放动画
        self.scale_animation = QPropertyAnimation(self.proxy_widget, b"scale")
        self.scale_animation.setDuration(600)
        self.scale_animation.setStartValue(0.0)
        self.scale_animation.setEndValue(1.0)
        self.scale_animation.setEasingCurve(QEasingCurve.Type.OutCubic)

        # 透明度动画
        self.opacity_animation = QPropertyAnimation(self.proxy_widget, b"opacity")
        self.opacity_animation.setDuration(300)
        self.opacity_animation.setStartValue(0.0)
        self.opacity_animation.setEndValue(1.0)

        self.scale_animation.start()
        self.opacity_animation.start()

if __name__ == "__main__":
    os.environ['QT_ENABLE_HIGHDPI_SCALING'] = '0'
    os.environ['QT_FONT_DPI'] = '120'

    app = QApplication(sys.argv)
    app.setStyle(QStyleFactory.create('windowsvista'))

    dialog = ExpandingDialog()
    dialog.exec()

方案二:无需QGraphicsView,直接在QDialog实现缩放

这种方案更轻量,通过自定义scale属性,在绘制时应用缩放变换,完全保留QDialog的exec()模态特性:

实现代码

from PyQt6.QtWidgets import (QApplication, QDialog, QStyleFactory)
from PyQt6.QtCore import Qt, QPropertyAnimation, QEasingCurve, pyqtProperty
from PyQt6.QtGui import QTransform, QPainter
from PyQt6 import uic
import sys
import os


class ExpandingDialog(QDialog):
    def __init__(self):
        super().__init__()
        uic.loadUi("Error.ui", self)
        self.setWindowFlag(Qt.WindowType.FramelessWindowHint)
        self.setAttribute(Qt.WidgetAttribute.WA_TranslucentBackground)
        self._scale = 0.0

    def paintEvent(self, event):
        painter = QPainter(self)
        painter.setRenderHint(QPainter.RenderHint.Antialiasing)
        # 以窗口中心为原点应用缩放变换
        transform = QTransform()
        center = self.rect().center()
        transform.translate(center.x(), center.y())
        transform.scale(self._scale, self._scale)
        transform.translate(-center.x(), -center.y())
        painter.setTransform(transform)
        super().paintEvent(event)

    @pyqtProperty(float)
    def scale(self):
        return self._scale

    @scale.setter
    def scale(self, value):
        self._scale = value
        self.update()

    def showEvent(self, event):
        self.start_animation()

    def start_animation(self):
        # 缩放动画
        self.scale_animation = QPropertyAnimation(self, b"scale")
        self.scale_animation.setDuration(600)
        self.scale_animation.setStartValue(0.0)
        self.scale_animation.setEndValue(1.0)
        self.scale_animation.setEasingCurve(QEasingCurve.Type.OutCubic)

        # 透明度动画
        self.opacity_animation = QPropertyAnimation(self, b"windowOpacity")
        self.opacity_animation.setDuration(300)
        self.opacity_animation.setStartValue(0.0)
        self.opacity_animation.setEndValue(1.0)

        self.scale_animation.start()
        self.opacity_animation.start()

if __name__ == "__main__":
    os.environ['QT_ENABLE_HIGHDPI_SCALING'] = '0'
    os.environ['QT_FONT_DPI'] = '120'

    app = QApplication(sys.argv)
    app.setStyle(QStyleFactory.create('windowsvista'))

    dialog = ExpandingDialog()
    dialog.exec()

效果说明

  • 两种方案都能实现你展示的中心缩放+淡入效果
  • 方案二更简洁,无需额外的Graphics组件,且原生支持exec()模态
  • 替换代码中的uic.loadUi("Error.ui", self)为你的UI文件路径即可使用

内容的提问来源于stack exchange,提问作者Edward

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.13 06:52:09