Самый большой вопрос: Что именно вы пытаетесь сделать? Что такое класс 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;
}
Если вы хотите увидеть, во всем мире, все слоты, которые вызываются с помощью системы metacall, вы можете сделать это. Параметризация шаблона базового класса позволяет гибко использовать любой класс приложений - скажем 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);
...
}
Благодарим за информацию. Чтобы принять ответ, я все равно хотел бы знать, для чего он используется, возможно, в реальном мире, и если есть что-либо из типа QEvent. – Rafe
Неверно, что 'QMetaCallEvent' создается всякий раз, когда вызывается связанный сигнал. Это сделало бы механизм сигнального слота намного медленнее, чем необходимо. –