How to intercept ALL signals emitted by a given event in Qt?
Asked Answered
D

5

9

I can imagine that there might be quite a few of them depending on the event, but at the same time, I guess this can be a best way to debug, and an interesting lesson.

Why would I need it? I'm using some custom class based on the QWidget, which does not expand when I de-attach a QDockWidget based in the same window. Knowing what signals are emitted when this dock widget is being de-attached would help me to chose which method I need to overwrite in my custom class.

In other words, I don't want to check every possible signal from the documentation, but just see which signals are emitted when I perform some action in my application.

Dur answered 15/1, 2010 at 14:4 Comment(0)
M
10

This isn't possible with any public API.

But, if you put your code into a QTestLib-based unit test, you can run the unit test with -vs to print out every emitted signal.

Mural answered 15/1, 2010 at 22:30 Comment(0)
S
7

You may want to take a look at the QSignalSpy class. I think though you have to connect manually the signal you want to spy.

Snowflake answered 15/1, 2010 at 14:17 Comment(0)
D
2

I don't think this is possible with Qt. You can

  • list all signals of a class using QMetaObject::method and QMetaMethod::methodType;
  • attach one of your own slots to all of those signals;
  • check who invoked a slot using QObject::sender.

But I'm stuck after this. I don't think that, besides the sender, any information can be obtained about how a slot got invoked.

Dunne answered 15/1, 2010 at 14:24 Comment(1)
Thanks for the advice! How do I do that? QMetaObject::method asks for a parameter. I'm not sure what I need to pass it.Irfan
I
2

If you're using PyQT5 instead of Qt5, you can use Python's introspection abilities to find all signals of any class and connect them to a dummy slot (of a dummy object).

#!/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)

The dummy slot now prints info about all signals emitted by an object. For example, if you spy on a random QLineEdit like this:

some_line_edit = QLineEdit(self)
spy_on all_signals(some_line_edit)

A possible log of entering and exiting the line edit might look like this:

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()'
Immanuel answered 31/7, 2019 at 16:14 Comment(0)
C
0

Check out signal spying. Got some great insight of QT library and spying on signals/slots.

Chrestomathy answered 3/11, 2010 at 11:12 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.