【问题标题】:How to intercept ALL signals emitted by a given event in Qt?如何拦截Qt中给定事件发出的所有信号?
【发布时间】:2011-01-05 12:47:54
【问题描述】:

我可以想象根据事件可能会有很多,但同时,我想这可能是调试的最佳方式,也是一个有趣的教训。

我为什么需要它?我正在使用一些基于QWidget 的自定义类,当我在同一窗口中取消附加QDockWidget 时,它不会扩展。知道当这个停靠小部件被解除附加时会发出什么信号将帮助我选择我需要在我的自定义类中覆盖的方法。

换句话说,我不想检查文档中所有可能的信号,而只想查看当我在应用程序中执行某些操作时发出了哪些信号。

【问题讨论】:

    标签: qt debugging pyqt signals-slots


    【解决方案1】:

    这对于任何公共 API 都是不可能的。

    但是,如果您将代码放入基于 QTestLib 的单元测试中,您可以使用 -vs 运行单元测试以打印出每个发出的信号。

    【讨论】:

      【解决方案2】:

      您可能想看看QSignalSpy 类。 我认为尽管您必须手动连接要监视的信号。

      【讨论】:

        【解决方案3】:

        我认为这在 Qt 中是不可能的。你可以

        • 使用 QMetaObject::method 和 QMetaMethod::methodType 列出一个类的所有信号;
        • 将您自己的插槽之一附加到所有这些信号;
        • 使用 QObject::sender 检查谁调用了插槽。

        但我在这之后被困住了。我不认为除了发送者之外,任何信息都可以获得关于一个槽是如何被调用的。

        【讨论】:

        • 感谢您的建议!我怎么做? QMetaObject::method 要求一个参数。我不确定我需要通过什么。
        【解决方案4】:

        如果您使用的是 PyQT5 而不是 Qt5,则可以使用 Python 的自省功能来查找任何类的所有信号并将它们连接到(虚拟对象的)虚拟插槽。

        #!/usr/bin/env python
        # -*- coding: utf-8 -*-
        from typing import Iterable
        
        from PyQt5.QtCore import pyqtBoundSignal
        from PyQt5.QtCore import pyqtSlot
        from PyQt5.QtCore import QObject
        
        
        def list_all_signals(obj: QObject) -> Iterable[pyqtBoundSignal]:
            attr_names = dir(obj)
            attributes = (getattr(obj, attr_name) for attr_name in attr_names)
            connectable = filter(lambda l: hasattr(l, "connect"), attributes)
        
            return connectable
        
        
        class SignalListener(QObject):
            @pyqtSlot()
            def universal_slot(self, *args, **kwargs):
                print("Signal caught" + 30 * "-")
                print("sender:", self.sender())
                meta_method = (
                    self.sender().metaObject().method(self.senderSignalIndex())
                )
                print("signal:", meta_method.name())
                print("signal signature:", meta_method.methodSignature())
        
        
        SIGNAL_LISTENER = SignalListener()
        
        
        def spy_on_all_signals(
            obj: QObject, listener: SignalListener = SIGNAL_LISTENER
        ):
            for signal in list_all_signals(obj):
                signal.connect(SIGNAL_LISTENER.universal_slot)
        

        虚拟插槽现在打印有关对象发出的所有信号的信息。 例如,如果您像这样监视随机 QLineEdit:

        some_line_edit = QLineEdit(self)
        spy_on all_signals(some_line_edit)
        

        进入和退出行编辑的可能日志如下所示:

        Signal caught ------------------------------
        sender: <PyQt5.QtWidgets.QLineEdit object at 0x7f220f7a3370>
        signal: b'cursorPositionChanged'
        signal signature: b'cursorPositionChanged(int,int)'
        Signal caught ------------------------------
        sender: <PyQt5.QtWidgets.QLineEdit object at 0x7f220f7a3370>
        signal: b'selectionChanged'
        signal signature: b'selectionChanged()'
        Signal caught ------------------------------
        sender: <PyQt5.QtWidgets.QLineEdit object at 0x7f220f7a3370>
        signal: b'selectionChanged'
        signal signature: b'selectionChanged()'
        Signal caught ------------------------------
        sender: <PyQt5.QtWidgets.QLineEdit object at 0x7f220f7a3370>
        signal: b'editingFinished'
        signal signature: b'editingFinished()'
        

        【讨论】:

          【解决方案5】:

          查看signal spying。深入了解 QT 库并监视信号/插槽。

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 1970-01-01
            • 2012-10-03
            • 2010-12-28
            • 2023-03-31
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2011-12-28
            相关资源
            最近更新 更多