Самый главный вопрос: Что именно вы пытаетесь сделать? Какой класс Qt получил эти события? Насколько я понимаю, вы пытаетесь сделать что-то сложным путем, так зачем беспокоиться?
QMetaCallEvent
– это событие, представляющее вызов слота всякий раз, когда подключение в очереди используется для вызова слота. Это могло произойти из-за срабатывания сигнала, который был подключен к слоту, или из-за использования QMetaObject::invoke
или QMetaObject::invokeMethod
. Бит соединения в очереди является важной частью! Соединения в очереди не по умолчанию используются для вызовов между объектами в одном и том же потоке, поскольку они несут накладные расходы на управление очередью событий, за исключением случаев, когда выполняется одно из двух следующих условий:
Вы предоставляете Qt::QueuedConnection
аргумент для QObject::connect
или QMetaObject::invoke[Method]
, или
thread()
принимающего объекта отличается от потока, из которого исходит вызов - во время вызова.
Класс событий QMetaCallEvent
содержит информация, необходимая для вызова слота. Он содержит отправителя QObject
и идентификатор его сигнала (если вызов исходит из соединения сигнал-слот), а также идентификатор целевого слота и аргументы, которые необходимо передать в слот.
Таким образом, вы можете проверить, является ли вызываемый слот тем, который вы хотите перехватить, а также какие аргументы ему были переданы. Например, если вы вызываете слот с одним параметром int
, то *reinterpret_cast<int*>(metaCallEvent->args()[1])
даст вам значение этого целого числа. Нулевой аргумент используется для возвращаемого значения, если оно есть, поэтому параметры индексируются с основанием 1.
Отказ от ответственности Поскольку класс QMetaCallEvent
является внутренним для реализации Qt, вы делаете двоичный файл вашего приложения полностью привязанным к конкретной версии Qt (вся основная.дополнительная версия) и вы теряете преимущества двоичной совместимости, предлагаемые Qt в основной версии. Ваш код все еще может компилироваться, но перестанет работать должным образом, когда вы переключитесь на другую второстепенную версию Qt!
Нижеприведенное относится к Qt 5.2.0, другие версии я не смотрел!
Итак, предположим, вы хотите перехватить вызов QLabel::setNum
. Вы бы поймали такие события следующим образом:
#include <private/qobject_p.h> // Declaration of QMetaCallEvent
bool Object::eventFilter(QObject * watched, QEvent * event) {
QLabel * label = qobject_cast<QLabel*>(watched);
if (! label || event->type() != QEvent::MetaCall) return false;
QMetaCallEvent * mev = static_cast<QMetaCallEvent*>(event);
static int setNumIdx = QLabel::staticMetaObject.indexOfSlot("setNum(int)");
if (mev->id() != setNumIdx) return false;
int num = *reinterpret_cast<int*>(mev->args()[1]);
// At this point, we can invoke setNum ourselves and discard the event
label->setNum(num);
return true;
}
Если вы хотите видеть глобально все слоты, которые вызываются с помощью системы метавызовов, вы также можете это сделать. Параметризация шаблона базового класса позволяет гибко использовать любой класс приложения — скажем, QCoreApplication
, QGuiApplication
, QApplication
или пользовательский тип.
template <class Base> class MetaCallWatcher : public Base {
MetaCallWatcher(int& argc, char** argv) : Base(argc, argv) {}
bool notify(QObject * receiver, QEvent * event) {
if (event->type() == QEvent::MetaCall) {
QMetaCallEvent * mev = static_cast<QMetaCallEvent*>(event);
QMetaMethod slot = receiver->metaObject()->method(mev->id());
qDebug() << "Metacall:" << receiver << slot.methodSignature();
}
return Base::notify(receiver, event);
}
}
int main(int argc, char ** argv) {
MetaCallWatcher<QApplication> app(argc, argv);
...
}
person
Kuba hasn't forgotten Monica
schedule
08.01.2014