Я хочу, чтобы объекту было доступно более одного обратного вызова, но определение any последующего обратного вызова в объекте перезаписывает все предыдущие обратные вызовы. Тем не менее, обратные вызовы оформлены, что, кажется, портит вещи. Как определить обратные вызовы уровня объекта, чтобы в них можно было использовать self?
В следующем примере, который вы можете запустить на любом компьютере с Python 3.x и PyQt5.11.x, спинбокс подключается к двум обратным вызовам valueChanged. Они называются A
и C
. Однако второй обратный вызов C
никогда не срабатывает, а третий обратный вызов D
срабатывает вместо этого. D
не должен срабатывать.
Обратные вызовы печатают свои буквы и значение spinbox, поэтому ожидаемый результат при вращении spinbox:
got A 1
got C 1
Тем не менее, фактический результат:
got A 1
got D 1
Это неправильно, потому что спинбокс подключен к
callbackA
self.callbackC
Я не знаю, почему вызывается D, поскольку я нигде не упоминаю об этом. Однако, если мы удалим любой из декораторов из C или D, они снова будут работать. Что я делаю не так?
Код, о котором идет речь:
from PyQt5 import QtWidgets
from PyQt5.QtCore import pyqtSlot
def silenceCallbacks(*elements):
"""Silence events for the duration of a callback. Mostly skipped for this reproduction."""
def silenceCallbacksOf(callback):
def silencedCallback(self, *args, **kwargs):
callback(self, *args, **kwargs)
return silencedCallback
return silenceCallbacksOf
@pyqtSlot(int)
@silenceCallbacks()
def callbackA(px: int):
#correctly called
print('got A', px)
@pyqtSlot(int) #this overwrites the last three functions
@silenceCallbacks()
def callbackB(px: int):
#correctly not called
print('got B', px)
class RecordingSettings(QtWidgets.QDialog):
@pyqtSlot(int)
@silenceCallbacks()
def callbackC(self, px: int):
#incorrectly not called
print('got C', px)
@pyqtSlot(int) #this overwrites the previous pyqtSlot-decorated function
@silenceCallbacks()
def callbackD(self, px: int):
#incorrectly called
print('got D', px)
def __init__(self, window):
super().__init__()
spin = QtWidgets.QSpinBox()
spin.valueChanged.connect(callbackA)
spin.valueChanged.connect(self.callbackC)
layout = QtWidgets.QVBoxLayout()
layout.addWidget(spin)
self.setLayout(layout)
self.show()
app = QtWidgets.QApplication([])
recSettingsWindow = RecordingSettings(app)
recSettingsWindow.show()
app.exec_()