0

我正在尝试制作无效的动画工具。我有一个按钮,当按下该按钮时,会将字段的背景颜色从红色设置为“正常”字段颜色。这很好用,但现在我想传入任意PyQt 小部件对象(可以是QLineEditQComboBox等)。这是我的动画处理程序的样子:

在此处输入图像描述

@QtCore.pyqtSlot(QtGui.QColor)
def invalid_animation_handler(color: QtGui.QColor) -> None:
    field.setStyleSheet(f"background-color: {QtGui.QColor(color).name()}")

目前它要求field在调用函数更改背景之前已经命名对象。我希望能够widget通过传入参数来动态传入 a 并动态设置样式表,如下所示:

@QtCore.pyqtSlot(QtGui.QColor)
def invalid_animation_handler(widget, color: QtGui.QColor) -> None:
    widget.setStyleSheet(f"background-color: {QtGui.QColor(color).name()}")

当我尝试这样做时,可以传递小部件,但是从WARNING_COLOR到的恒定颜色变化NORMAL_COLOR不再起作用。我也不想把它放到一个类中,因为它必须是即时的。我的目标是能够调用一个函数来从任何地方开始动画,而不必按下按钮。期望的目标是这样的:

class VariantAnimation(QtCore.QVariantAnimation):
    """VariantAnimation: Implement method for QVariantAnimation to fix pure virtual method in PyQt5 -> PyQt4"""
    def updateCurrentValue(self, value):
        pass

@QtCore.pyqtSlot(QtGui.QColor)
def invalid_animation_handler(widget, color: QtGui.QColor) -> None:
    widget.setStyleSheet(f"background-color: {QtGui.QColor(color).name()}")

def invalid_animation(widget):
    return VariantAnimation(startValue=ERROR_COLOR, endValue=NORMAL_COLOR, duration=ANIMATION_DURATION, valueChanged=lambda: invalid_animation_handler(widget))

def start_invalid_animation(animation_handler) -> None:
    if animation_handler.state() == QtCore.QAbstractAnimation.Running:
        animation_handler.stop()
    animation_handler.start()

field = QtGui.QLineEdit()
field_animation_handler = invalid_animation(field)

# Goal is to make a generic handler to start the animation
start_invalid_animation(field_animation_handler)

最小的工作示例

import sys
from PyQt4 import QtCore, QtGui

class VariantAnimation(QtCore.QVariantAnimation):
    """VariantAnimation: Implement method for QVariantAnimation to fix pure virtual method in PyQt5 -> PyQt4"""
    def updateCurrentValue(self, value):
        pass

@QtCore.pyqtSlot(QtGui.QColor)
def invalid_animation_handler(color: QtGui.QColor) -> None:
    field.setStyleSheet(f"background-color: {QtGui.QColor(color).name()}")

def start_field_invalid_animation() -> None:
    if field_invalid_animation.state() == QtCore.QAbstractAnimation.Running:
        field_invalid_animation.stop()
    field_invalid_animation.start()
    
NORMAL_COLOR = QtGui.QColor(25,35,45)
SUCCESSFUL_COLOR = QtGui.QColor(95,186,125)
WARNING_COLOR = QtGui.QColor(251,188,5)
ERROR_COLOR = QtGui.QColor(247,131,128)
ANIMATION_DURATION = 1500

if __name__== '__main__':
    app = QtGui.QApplication(sys.argv)
    button = QtGui.QPushButton('Animate field background')
    button.clicked.connect(start_field_invalid_animation)
    field = QtGui.QLineEdit()
    field_invalid_animation = VariantAnimation(startValue=ERROR_COLOR, endValue=NORMAL_COLOR, duration=ANIMATION_DURATION, valueChanged=invalid_animation_handler)

    mw = QtGui.QMainWindow()
    layout = QtGui.QHBoxLayout()
    layout.addWidget(button)
    layout.addWidget(field)
    window = QtGui.QWidget()
    window.setLayout(layout)
    mw.setCentralWidget(window)
    mw.show()
    sys.exit(app.exec_())
4

2 回答 2

2

我不明白您为什么不想要上课,但 IMO 是最合适的解决方案。逻辑是存储允许更改属性的可调用对象并在 updateCurrentValue 中调用它。

目前我没有安装 PyQt4,所以我用 PyQt5 实现了逻辑,但我认为更改导入并不困难。

import sys
from dataclasses import dataclass
from functools import partial
from typing import Callable

from PyQt5.QtCore import QAbstractAnimation, QObject, QVariant, QVariantAnimation
from PyQt5.QtGui import QColor
from PyQt5.QtWidgets import (
    QApplication,
    QHBoxLayout,
    QLineEdit,
    QMainWindow,
    QPushButton,
    QWidget,
)


@dataclass
class VariantAnimation(QVariantAnimation):
    widget: QWidget
    callback: Callable[[QWidget, QVariant], None]
    start_value: QVariant
    end_value: QVariant
    duration: int
    parent: QObject = None

    def __post_init__(self) -> None:
        super().__init__()
        self.setStartValue(self.start_value)
        self.setEndValue(self.end_value)
        self.setDuration(self.duration)
        self.setParent(self.parent)

    def updateCurrentValue(self, value):
        if isinstance(self.widget, QWidget) and callable(self.callback):
            self.callback(self.widget, value)


def invalid_animation_handler(widget: QWidget, color: QColor) -> None:
    widget.setStyleSheet(f"background-color: {QColor(color).name()}")


def start_field_invalid_animation(animation: QAbstractAnimation) -> None:
    if animation.state() == QAbstractAnimation.Running:
        animation.stop()
    animation.start()


NORMAL_COLOR = QColor(25, 35, 45)
SUCCESSFUL_COLOR = QColor(95, 186, 125)
WARNING_COLOR = QColor(251, 188, 5)
ERROR_COLOR = QColor(247, 131, 128)
ANIMATION_DURATION = 1500

if __name__ == "__main__":
    app = QApplication(sys.argv)
    button = QPushButton("Animate field background")

    field = QLineEdit()
    animation = VariantAnimation(
        widget=field,
        callback=invalid_animation_handler,
        start_value=ERROR_COLOR,
        end_value=NORMAL_COLOR,
        duration=ANIMATION_DURATION,
    )

    button.clicked.connect(partial(start_field_invalid_animation, animation))

    mw = QMainWindow()
    layout = QHBoxLayout()
    layout.addWidget(button)
    layout.addWidget(field)
    window = QWidget()
    window.setLayout(layout)
    mw.setCentralWidget(window)
    mw.show()
    sys.exit(app.exec_())
于 2021-10-05T04:24:11.367 回答
0

另一种解决方案,而不是使用@eyllanesc 的使用部分的方法。一种解决方法是更改​​函数的范围,并将设置样式表的实际函数放在与父函数相同的范围内。

class VariantAnimation(QtCore.QVariantAnimation):
    """VariantAnimation: Implement method for QVariantAnimation to fix pure virtual method in PyQt5 -> PyQt4"""
    def updateCurrentValue(self, value):
        pass

def invalid_animation(widget):
    @QtCore.pyqtSlot(QtGui.QColor)
    def invalid_animation_handler(color: QtGui.QColor) -> None:
        widget.setStyleSheet(f"background-color: {QtGui.QColor(color).name()}")

    return VariantAnimation(startValue=ERROR_COLOR, endValue=NORMAL_COLOR, duration=ANIMATION_DURATION, valueChanged=invalid_animation_handler)

def start_invalid_animation(animation_handler) -> None:
    if animation_handler.state() == QtCore.QAbstractAnimation.Running:
        animation_handler.stop()
    animation_handler.start()

field = QtGui.QLineEdit()
field_animation_handler = invalid_animation(field)

# Goal is to make a generic handler to start the animation
start_invalid_animation(field_animation_handler)
于 2021-10-05T04:27:01.027 回答