Как перехватить ВСЕ сигналы, излучаемые данным событием в Qt?

Я могу представить, что их может быть довольно много, в зависимости от события, но в то же время, я думаю, это может быть лучшим способом отладки и интересным уроком.

Зачем мне это нужно? Я использую некоторый пользовательский класс, основанный на QWidget, который не расширяется, когда я де-прикрепить QDockWidget основан в том же окне. Знание того, какие сигналы испускаются при отсоединении этого виджета, поможет мне выбрать метод, который мне нужно перезаписать в моем пользовательском классе.

Другими словами, я не хочу проверять каждый возможный сигнал из документации, но просто вижу, какие сигналы испускаются, когда я выполняю какое-то действие в своем приложении.

4 ответа

Решение

Это невозможно с любым открытым API.

Но если вы поместите свой код в модульный тест на основе QTestLib, вы можете запустить его с помощью -vs распечатать каждый излучаемый сигнал.

Вы можете взглянуть на класс QSignalSpy. Я думаю, что вы должны вручную подключить сигнал, который вы хотите шпионить.

Я не думаю, что это возможно с Qt. Вы можете

  • перечислить все сигналы класса, используя QMetaObject::method и QMetaMethod::methodType;
  • прикрепите один из ваших собственных слотов ко всем этим сигналам;
  • проверьте, кто вызвал слот, используя QObject::sender.

Но я застрял после этого. Я не думаю, что, кроме отправителя, можно получить любую информацию о том, как вызывался слот.

Если вы используете 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()'

Проверьте шпионаж сигнала. Получил отличное представление о библиотеке QT и слежке за сигналами / слотами.

Другие вопросы по тегам