将动态小部件对象传递给 QVariantAnimation valueChanged 信号处理程序
Posted
技术标签:
【中文标题】将动态小部件对象传递给 QVariantAnimation valueChanged 信号处理程序【英文标题】:Pass in dynamic widget object to QVariantAnimation valueChanged signal handler 【发布时间】:2021-11-25 09:22:28 【问题描述】:我正在尝试制作无效的动画工具。我有一个按钮,当按下该按钮时,会将字段的背景颜色从红色设置为“正常”字段颜色。这很好用,但现在我想传入任何任意 PyQt 小部件对象(可以是QLineEdit
、QComboBox
等)。这是我的动画处理程序的样子:
@QtCore.pyqtSlot(QtGui.QColor)
def invalid_animation_handler(color: QtGui.QColor) -> None:
field.setStyleSheet(f"background-color: QtGui.QColor(color).name()")
目前它要求field
对象在调用函数更改背景之前已经命名。我希望能够动态传入 widget
并通过传入参数来动态设置样式表,如下所示:
@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_())
【问题讨论】:
你说:我也不想把它放到一个类中,因为它必须是 on-the-fly,我不明白你的话,为什么要一个上课给你带来问题? @eyllanesc 我正在尝试制作一个通用处理程序来执行无效/有效动画。我已经在我的班级中创建了大量的小部件,例如self.button1
、self.button2
或 self.field1
,所以我只想创建处理程序,然后在需要时调用它
我看到this post 使用了一个类,但我想即时做同样的事情
我了解 on-the-fly 意味着在链接的示例中,您不希望在 GUI 中实现“on_color_change”,对吗?跨度>
那个链接的例子有QLineEdit
作为一个类继承,所以要改变它的背景self.setStyleSheet()
。我正在尝试实现一种技术,您可以将任意小部件作为参数传递给“on_color_change”函数。所以不是self
,而是passed_widget_object.setStyleSheet()
【参考方案1】:
我不明白您为什么不想要上课,但 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_())
【讨论】:
谢谢 :) 我通过更改以下范围找到了另一种方法【参考方案2】:另一种解决方案,而不是使用@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)
【讨论】:
以上是关于将动态小部件对象传递给 QVariantAnimation valueChanged 信号处理程序的主要内容,如果未能解决你的问题,请参考以下文章
Javascript ajax 将动态创建的 json 对象传递给 Web 服务