gpt4 book ai didi

python - 在另一个装饰器之前使用 PyQt 4's ' pyqtSlot' 装饰器的奇怪行为

转载 作者:太空宇宙 更新时间:2023-11-04 03:41:04 26 4
gpt4 key购买 nike

在用不同装饰器装饰的函数前使用 QtCore.pyqtSlot 装饰器时,我遇到了一个奇怪的问题。下面的问题演示了这个问题。它用一个按钮实例化一个简约的 Qt 程序。按下按钮时,会发生以下情况:

(1) 信号“signal_A”和“signal_B”分别连接到实例 method_A 和 method_B。

(2)发出signal_A和signal_B信号。

(3) 预期 行为是执行 method_A 和 method_B。然而,事实证明,signal_A 和 signal_B 都会触发 method_A 或 method_B(奇怪的是,这是不确定的,并且每次运行程序时都不同!)。

这似乎是一个错误。

使用 PyQt4 绑定(bind)到 Qt 时会出现此问题。它在使用 PySide 时不存在(使用“--pyside”参数进行验证)。我在 Python 2 和 3 以及 Windows 和 Linux 中都看到了这个问题。

问题似乎与在“@QtS​​lot”和方法定义之间插入装饰器有关。测试程序中的“null_decorator”应该什么也不做(如果我对装饰器的理解是正确的),但是当我删除它时程序的行为会发生变化。

如果能帮助理解这里发生的事情,我们将不胜感激。

#! /usr/bin/env python3

import sys, time

if "--pyside" not in sys.argv:
# default to PyQt4 bindings
from PyQt4 import QtCore, QtGui
QtSignal = QtCore.pyqtSignal
QtSlot = QtCore.pyqtSlot
else:
# alternatively, use PySide bindings
from PySide import QtCore, QtGui
QtSignal = QtCore.Signal
QtSlot = QtCore.Slot


def null_decorator(f):
def null_decorator_wrapper(self, *args, **kwargs):
return f(self, *args, **kwargs)
return null_decorator_wrapper


class TestClass(QtCore.QObject):

def __init__(self, *args, **kwargs):
super(TestClass, self).__init__(*args, **kwargs)

@QtSlot()
@null_decorator
def method_A(self):
print("method_A() executing!")

@QtSlot()
@null_decorator
def method_B(self):
print("method_B() executing!")


class DemonstrateProblemButton(QtGui.QPushButton):

signal_A = QtSignal()
signal_B = QtSignal()

def __init__(self, *args, **kwargs):
super(DemonstrateProblemButton, self).__init__(*args, **kwargs)
self.clicked.connect(self.on_clicked)

@QtSlot()
def on_clicked(self):

# Create TestClass instance
instance = TestClass()

# connect the signals
self.signal_A.connect(instance.method_A)
self.signal_B.connect(instance.method_B)

# emit the signals
self.signal_A.emit()
self.signal_B.emit()

def main():

# instantiate the GUI application
app = QtGui.QApplication(sys.argv)

button = DemonstrateProblemButton("Demonstrate Problem")
button.show()

return QtGui.QApplication.exec_()


if __name__ == "__main__":
exitcode = main()
sys.exit(exitcode)

最佳答案

像这样使用 null_decorator 将导致所有插槽具有相同的名称(即“null_decorator_wrapper”),因此 PyQt 可能无法区分它们。

在您的示例中有多种方法可以解决此问题。

首先,您可以确保插槽具有不同的签名:

@QtSlot()
@null_decorator
def method_A(self):
print("method_A() executing!")

@QtSlot(int)
@null_decorator
def method_B(self, foo=0):
print("method_B() executing!")

其次,您可以明确指定插槽名称:

@QtSlot(name="method_A")
@null_decorator
def method_A(self):
print("method_A() executing!")

@QtSlot(name="method_B")
@null_decorator
def method_B(self, foo=0):
print("method_B() executing!")

第三,您可以在 null_decorator 中自动设置名称:

def null_decorator(f):
def null_decorator_wrapper(self, *args, **kwargs):
return f(self, *args, **kwargs)
null_decorator_wrapper.__name__ = f.__name__
return null_decorator_wrapper

PS:pyqtSlot 装饰器的行为在 PyQt docs 中有明确说明。 (特别是,请参阅name 参数的说明),当然不是错误。

关于python - 在另一个装饰器之前使用 PyQt 4's ' pyqtSlot' 装饰器的奇怪行为,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/26428375/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com