Python装饰器聚合PyQt信号

| 我经常会有很多信号,理想情况下可以一次全部处理。例如,可以将触发OpenGL窗口更新的信号汇总为一个信号。另一个示例是弄脏表中一行的信号。 理想情况下,我希望装饰器生成类似下面的代码(在START和END之间):
#!/usr/bin/env python

from PyQt4.QtCore import *
from PyQt4.QtGui import *
from functools import wraps
import signal
import sys

signal.signal(signal.SIGINT, signal.SIG_DFL)

class AggregateManager:
    def __init__(self):
        self.clear()

    def clear(self):
        self.sent = False
        self.value = 0

    def aggregate(self, other):
        send = not self.sent
        self.sent = True
        self.value += other
        return send


class A(QObject):
    def __init__(self):
        super().__init__()
    # START
        self.generated_signal.connect(self.slot, Qt.QueuedConnection)
        self.slot_manager = AggregateManager()

    @pyqtSlot(int)
    def decorated_slot(self, *args):
        me = self.slot_manager
        if me.aggregate(*args):
            print(\"Sending\")
            self.generated_signal.emit()

    generated_signal = pyqtSignal()

    @pyqtSlot()
    def slot(self):
        me = self.slot_manager
        print(\"Received\", me.value)
        me.clear()
    # END


class B(QObject):
    signal = pyqtSignal(int)


a = A()
b = B()

b.signal.connect(a.decorated_slot)

for i in range(10):
    b.signal.emit(i)

app = QApplication(sys.argv)
sys.exit(app.exec_())
这样,对发送到decorated_slot的许多信号进行一次对“ 1”的调用。如何使用Python装饰器替换START和END之间的所有内容?     
已邀请:
        这是我到目前为止的内容。唯一的问题是pyqtSignal装饰器似乎从堆栈跟踪中获取了一些东西,而且我不知道有什么方法可以覆盖它,这是PyQt设计上的明显缺陷。
#!/usr/bin/env python

from PyQt4.QtCore import *
from PyQt4.QtGui import *
from functools import wraps
import signal
import sys

signal.signal(signal.SIGINT, signal.SIG_DFL)

class SetAdder:
    def __init__(self):
        self.clear()

    def clear(self):
        self.value = set()

    def aggregate(self, other):
        send = not self.value
        self.sent = True
        self.value.add(other)
        return send


# This class decorator adds nameSlot, nameAuxSignal, nameAuxSlot, and
# name_manager.  Signals should be connected to nameSlot.  They will cause
# the function \'name\' to be called with aggregated values.
def aggregated_slot_class_decorator(list_):
    def class_decorator(cls):
        for manager_type, name, *args in list_:
            signal_name = name + \"AuxSignal\"
            slot_a_name = name + \"Slot\"
            slot_b_name = name + \"AuxSlot\"
            manager_name = name + \"_manager\"

            def slot_a(self, *args_):
                manager = getattr(self, manager_name)
                if manager.aggregate(*args_):
                    print(\"Sending\")
                    getattr(self, signal_name).emit()

            def slot_b(self):
                manager = getattr(self, manager_name)
                getattr(self, name)(manager.value)
                manager.clear()

            setattr(cls, slot_a_name,
                    pyqtSlot(cls, *args, name=slot_a_name)(slot_a))
            setattr(cls, slot_b_name,
                    pyqtSlot(cls, name=slot_b_name)(slot_b))

            orig_init = cls.__init__
            def new_init(self, *args_, **kwargs):
                orig_init(self, *args_, **kwargs)
                getattr(self, signal_name).connect(getattr(self, slot_b_name),
                                                   Qt.QueuedConnection)
                setattr(self, manager_name, manager_type())
            cls.__init__ = new_init
            #setattr(cls, signal_name, pyqtSignal())
        return cls
    return class_decorator


@aggregated_slot_class_decorator([(SetAdder, \'test\', int)])
class A(QObject):
    def __init__(self):
        super().__init__()

    testAuxSignal = pyqtSignal()

    def test(self, value):
        print(\"Received\", value)


class B(QObject):
    signal = pyqtSignal(int)


a = A()
b = B()

b.signal.connect(a.testSlot)

for i in range(10):
    b.signal.emit(i % 5)

app = QApplication(sys.argv)
sys.exit(app.exec_())
输出:
Sending
Received {0, 1, 2, 3, 4}
    
        我已经做过类似的事情,但是范围更广,粒度也更小。我创建了一个上下文管理器来临时断开插槽。这样一来,很明显,您可以禁用代码块中的某些插槽,然后重新连接它们,并发出在其间丢失的任何内容。 源在这里,我在下面粘贴了代码段。这可能不是您想要的,但在类似情况下对我很有用。我想做一些可能发出“中间”信号的事情,而从长远来看,“中间”的变化并不重要。因此,使用此上下文管理器,我可以禁用噪声信号,然后在需要时仅将其发出一次。这样可以避免很多中间状态更改。 一个很好的例子是在一个循环中设置PyQt QCheckboxes。您可以循环调用
checkbox.setChecked()
,但是每个复选框都会发出一堆信号。但是,您可以使用下面的上下文管理器来禁用
stateChanged
信号的任何插槽,并在自己获得'final \'结果后立即发出
stateChanged
信号。
from contextlib import contextmanager

@contextmanager
def slot_disconnected(signal, slot):
    \"\"\"
    Create context to perform operations with given slot disconnected from
    given signal and automatically connected afterwards.

    usage:
        with slot_disconnected(chkbox.stateChanged, self._stateChanged):
            foo()
            bar()
    \"\"\"

    signal.disconnect(slot)
    yield
    signal.connect(slot)
    

要回复问题请先登录注册