When using the pyqt signals of the UI elements such as buttons with decorated methods, the signal doesn’t seem to work. Please find below the minimum reproducible code.
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_())
In the above code if the button is clicked the call to the button_action function fails with the following message: TypeError: button_action() takes 1 positional argument but 2 were given. But the code works alright when I don’t use the decorator (ui_decorator), even though it still takes only 1 positional argument.
Thanks
>Solution :
When PyQt calls a slot (which can be any callable) it does not just "call" it. In order to achieve the behaviour that additional slot parameters are ignored it analyzes the callable and only passes the appropriate number of parameters. You render this mechanism useless by having your decorator return a callable that accepts any number of parameters and simply passes all of them on to the actual function.
You have two options:
- Adjust your decorator so that it returns a callable that accepts exactly the right amount of parameters (I suspect that to be rather difficult).
- Use the PyQt
pyqtSlotdecorator on top of your own decorator. That decorator defines the signature of the slot and makes the above mentioned behaviour working again, because PyQt then knows that the slot has no parameters:
@pyqtSlot()
@ui_decorator
def button_action(self):
print("Button Clicked")