2012-06-04 6 views
3

У меня есть фильтр событий, и я заметил, когда я нажимаю, чтобы развернуть/свернуть ветвь дерева, я получаю QEvent::MetaCall. Я думал об использовании этого, чтобы свернуть собственный код расширения/свернуть, но я не знаю, как получить какую-либо информацию, такую ​​как индекс элемента.Что такое QMetaCallEvent и как получить доступ к его деталям?

Есть ли что-нибудь из этого типа событий MetaCall?

я обнаружил, что кто-то задал этот же вопрос на другом сайте, но без ответа, здесь: http://www.qtcentre.org/threads/37525-How-to-filter-QEvent-MetaCall

Что это событие обычно используется?

ответ

0

Событие типа QEvent::MetaCall создается, когда выдается сигнал, который подключен к слоту в принимающем QObject. Реакция на это событие в пользовательском обработчике фильтра/события, похоже, обходит самую мощную функцию Qt - архитектуру сигнального слота. Вероятно, лучше узнать, какой слот называется, и если этот слот виртуальный, чтобы вы могли его перегрузить.

+0

Благодарим за информацию. Чтобы принять ответ, я все равно хотел бы знать, для чего он используется, возможно, в реальном мире, и если есть что-либо из типа QEvent. – Rafe

+0

Неверно, что 'QMetaCallEvent' создается всякий раз, когда вызывается связанный сигнал. Это сделало бы механизм сигнального слота намного медленнее, чем необходимо. –

-2

QEvent::MetaCall используется для подачи сигналов поперечной резьбы.

6

Самый большой вопрос: Что именно вы пытаетесь сделать? Что такое класс Qt, который получил эти события? Насколько я понимаю, вы пытаетесь сделать что-то трудное, так зачем беспокоиться?

QMetaCallEvent - событие, представляющее вызов слота, когда в очереди. используется для вызова слота. Это может быть связано с сигнальной стрельбой, которая была подключена к слоту или из-за использования QMetaObject::invoke или QMetaObject::invokeMethod. Очередной бит соединения является важной частью! Очереди соединений являются не по умолчанию используется для вызовов между объектами в том же потоке, так как они имеют накладные расходы на управление очередью событий, если ни одна из этих двух условий, ниже не верно:

  1. Вы предоставляете Qt::QueuedConnection аргумент QObject::connect или QMetaObject::invoke[Method], или

  2. принимающий объекта, 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); 
    ... 
} 
+0

Я не могу включить 'private/qobject_p.h', компилятор doensn't видеть его. – Efog

+0

@Efog У вас должна быть полная установка Qt из источников. В вашем случае источников нет, поэтому закрытых заголовков тоже нет. –

+0

Это работает до тех пор, пока вы используете старые строки на основе сигналов/слотов. С помощью указателей функций QMetaCallEvent.id() больше не содержит полезной информации. Это лучшее, что я мог бы выжать из новых соединений с сигналом/слотом: https://gist.github.com/webmaster128/2d4df2e46818d4e76fb7f7b8940c841a –