与装饰器一起使用时 pyqt 信号问题
Issue with pyqt signals when used with decorators
当使用 UI 元素的 pyqt 信号时,例如带有修饰方法的按钮,信号似乎不起作用。请在下面找到最小可重现代码。
import sys
from PyQt5.QtWidgets import (QWidget, QToolTip, QPushButton, QApplication)
from PyQt5.QtGui import QFont
def ui_decorator(target_func):
def call(self, *args, **kwargs):
print("Init.")
ret_code = target_func(self, *args, **kwargs)
print("Deinit.")
return ret_code
return call
class Example(QWidget):
def __init__(self):
super().__init__()
self.initUI()
def initUI(self):
QToolTip.setFont(QFont('SansSerif', 10))
self.setToolTip('This is a <b>QWidget</b> widget')
btn = QPushButton('Button', self)
btn.setToolTip('This is a <b>QPushButton</b> widget')
btn.clicked.connect(self.button_action)
btn.resize(btn.sizeHint())
btn.move(50, 50)
self.setGeometry(300, 300, 300, 200)
self.setWindowTitle('Tooltips')
self.show()
@ui_decorator
def button_action(self):
print("Button Clicked")
if __name__ == '__main__':
app = QApplication(sys.argv)
ex = Example()
sys.exit(app.exec_())
在上面的代码中,如果单击按钮,对 button_action
函数的调用将失败,并显示以下消息:TypeError: button_action() takes 1 positional argument but 2 were given
。但是当我不使用装饰器时代码工作正常(ui_decorator
),即使它仍然只需要 1 个位置参数。
谢谢
当 PyQt 调用一个插槽(可以是任何可调用的)时,它不只是“调用”它。为了实现忽略附加槽参数的行为,它分析可调用对象并仅传递适当数量的参数。通过让装饰器 return 接受任意数量的参数并将所有参数简单地传递给实际函数的可调用对象,您可以使这种机制变得无用。
您有两个选择:
- 调整您的装饰器,使其return成为一个可以接受正确数量参数的可调用对象(我怀疑这相当困难)。
- 在您自己的装饰器之上使用 PyQt
pyqtSlot
decorator。该装饰器定义槽的签名并使上述行为再次起作用,因为 PyQt 然后知道槽没有参数:
@pyqtSlot()
@ui_decorator
def button_action(self):
print("Button Clicked")
当使用 UI 元素的 pyqt 信号时,例如带有修饰方法的按钮,信号似乎不起作用。请在下面找到最小可重现代码。
import sys
from PyQt5.QtWidgets import (QWidget, QToolTip, QPushButton, QApplication)
from PyQt5.QtGui import QFont
def ui_decorator(target_func):
def call(self, *args, **kwargs):
print("Init.")
ret_code = target_func(self, *args, **kwargs)
print("Deinit.")
return ret_code
return call
class Example(QWidget):
def __init__(self):
super().__init__()
self.initUI()
def initUI(self):
QToolTip.setFont(QFont('SansSerif', 10))
self.setToolTip('This is a <b>QWidget</b> widget')
btn = QPushButton('Button', self)
btn.setToolTip('This is a <b>QPushButton</b> widget')
btn.clicked.connect(self.button_action)
btn.resize(btn.sizeHint())
btn.move(50, 50)
self.setGeometry(300, 300, 300, 200)
self.setWindowTitle('Tooltips')
self.show()
@ui_decorator
def button_action(self):
print("Button Clicked")
if __name__ == '__main__':
app = QApplication(sys.argv)
ex = Example()
sys.exit(app.exec_())
在上面的代码中,如果单击按钮,对 button_action
函数的调用将失败,并显示以下消息:TypeError: button_action() takes 1 positional argument but 2 were given
。但是当我不使用装饰器时代码工作正常(ui_decorator
),即使它仍然只需要 1 个位置参数。
谢谢
当 PyQt 调用一个插槽(可以是任何可调用的)时,它不只是“调用”它。为了实现忽略附加槽参数的行为,它分析可调用对象并仅传递适当数量的参数。通过让装饰器 return 接受任意数量的参数并将所有参数简单地传递给实际函数的可调用对象,您可以使这种机制变得无用。
您有两个选择:
- 调整您的装饰器,使其return成为一个可以接受正确数量参数的可调用对象(我怀疑这相当困难)。
- 在您自己的装饰器之上使用 PyQt
pyqtSlot
decorator。该装饰器定义槽的签名并使上述行为再次起作用,因为 PyQt 然后知道槽没有参数:
@pyqtSlot()
@ui_decorator
def button_action(self):
print("Button Clicked")