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

如何在PyQt6控件中实现CSS :after伪类的按钮动效

PyQt6实现CSS :after伪类扫光按钮效果

Qt Style Sheet(QSS)本身不支持CSS的:after、:before伪类,你需要的扫光效果可以通过重写控件绘制方法+属性动画的方式实现,完整可运行代码如下:

from PyQt6.QtCore import QRect, Qt, QPropertyAnimation, pyqtProperty, QEasingCurve
from PyQt6.QtGui import QEnterEvent, QPainter, QColor
from PyQt6.QtWidgets import QApplication, QMainWindow, QPushButton


class QButton(QPushButton):
    def __init__(self, parent=None):
        super().__init__(parent)
        self.setText("Welcome")
        # 扫光效果相关属性
        self._sweep_offset = -75  # 扫光条水平偏移量
        self.sweep_angle = 35  # 扫光条旋转角度
        self.sweep_opacity = 0.8  # 扫光条透明度
        
        # 初始化动画
        self.sweep_anim = QPropertyAnimation(self, b"sweep_offset")
        self.sweep_anim.setDuration(1000)
        self.sweep_anim.setEasingCurve(QEasingCurve.Type.OutCubic)
        
        # 基础样式
        self.setStyleSheet("""
            QPushButton{
                background-color: #2E3440;
                letter-spacing: 0.1em;
                font-size: 14px;
                font-weight: 400;
                text-decoration: none;
                color: #FFF;
                border: 4px solid #4C566A;
                box-shadow:0px 0px 0px 1px #4C566A inset;
            }
            QPushButton:hover{
                border: 4px solid #666;
                background-color: #D8DEE9;
                box-shadow:0px 0px 0px 4px #EEE inset;
                letter-spacing: 0.13em;
                color: #2E3440;
            }
        """)
        self.setFlat(True)
        self.setCursor(Qt.CursorShape.PointingHandCursor)
        self.setGeometry(QRect(200, 200, 200, 50))

    def setText(self, text: str):
        super().setText(text.upper())

    # 定义扫光偏移属性,供动画调用
    @pyqtProperty(int)
    def sweep_offset(self):
        return self._sweep_offset

    @sweep_offset.setter
    def sweep_offset(self, value):
        self._sweep_offset = value
        self.update()  # 触发重绘

    def paintEvent(self, event):
        # 先绘制按钮基础内容
        super().paintEvent(event)
        # 绘制扫光条
        painter = QPainter(self)
        painter.setRenderHint(QPainter.RenderHint.Antialiasing)
        painter.setClipRect(self.rect())  # 限制绘制区域在按钮内部
        painter.setOpacity(self.sweep_opacity)
        # 旋转坐标系
        painter.translate(self._sweep_offset, 0)
        painter.rotate(self.sweep_angle)
        # 绘制半透明白色矩形
        painter.fillRect(QRect(0, -50, 50, 155), QColor(255, 255, 255))
        painter.end()

    def enterEvent(self, event: QEnterEvent) -> None:
        super().enterEvent(event)
        # 启动扫光动画:从左到右扫过
        self.sweep_anim.setStartValue(-75)
        self.sweep_anim.setEndValue(self.width() + 50)
        self.sweep_anim.start()

    def leaveEvent(self, event) -> None:
        super().leaveEvent(event)
        # 重置扫光位置
        self.sweep_offset = -75


class Renderer:
    def __init__(self, main_window: QMainWindow) -> None:
        self.main_window = main_window

    def render(self):
        self.button = QButton(self.main_window)


if __name__ == "__main__":
    app = QApplication([])
    window = QMainWindow()
    window.resize(600, 400)
    renderer = Renderer(window)
    renderer.render()
    window.show()
    exit(app.exec())

核心实现逻辑说明

  • 自定义动画属性:通过pyqtProperty定义扫光条偏移属性,使用QPropertyAnimation驱动属性变化,复现CSS的transition动画效果,缓动曲线和时长与原CSS完全对齐
  • 自定义绘制:重写paintEvent方法,在按钮原有样式之上绘制斜切的半透明白色扫光条,通过setClipRect限制绘制区域不会超出按钮边界,对应原CSS中overflow: hidden的效果
  • 样式复用:基础的按钮背景、边框、文字样式直接用QSS实现,hover状态的样式变化直接写在QSS的:hover伪类中,不需要在事件中手动切换样式

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.04 15:18:01