2012-06-04 2 views
3

이벤트 필터가 있고 나뭇 가지를 펼치거나 접을 때 나타났습니다. QEvent::MetaCall이 나타납니다. 이 방법을 사용하여 확장/축소 코드를 굴릴 생각 이었지만 항목의 색인과 같은 정보를 얻는 방법을 모르겠습니다.QMetaCallEvent 란 무엇이며 세부 정보에 액세스하는 방법은 무엇입니까?

이 MetaCall 이벤트 유형에서 사용할 수있는 것이 있습니까?

나는 누군가가 다른 사이트에서이 같은 질문을하지만, 여기에 대답하지 않고 있었다 발견 : http://www.qtcentre.org/threads/37525-How-to-filter-QEvent-MetaCall

이 이벤트는 일반적으로 무엇을 사용합니까?

답변

0

QEvent::MetaCall -type 이벤트는 수신 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과 시그널 ID (호출이 신호 슬롯 연결에서 오는 경우), 대상 슬롯 식별자 및 슬롯으로 전달되어야하는 인수가 포함됩니다.

따라서 호출 된 슬롯이 가로 채기를 원하는 슬롯인지 여부와 전달 된 인수를 확인할 수 있습니다. 예를 들어, 단일 int 매개 변수가있는 슬롯을 호출하는 경우 *reinterpret_cast<int*>(metaCallEvent->args()[1])은 해당 정수 값을 제공합니다. QMetaCallEvent 클래스 때문에 제로 번째의 인수가 반환 값에 사용됩니다 (있는 경우), 그래서 매개 변수가 면책 1.

베이스 색인, 당신은 응용 프로그램의 바이너리에 묶여 만들고있어 Qt의 구현 내부에 전체 Qt 버전 (전공.부 버전), 주요 버전에서 Qt가 제공하는 바이너리 호환성의 이점을 잃게됩니다. Qt의 다른 부 버전으로 전환 할 때 코드가 여전히 컴파일 될 수 있지만 제대로 작동하지 않습니다!

아래 내용은 Qt 5.2.0에 적용됩니다. 다른 버전은 보지 않았습니다!

따라서 QLabel::setNum에 대한 호출을 가로 채기를 원한다고 가정하십시오. 다음과 같이 이러한 이벤트를 잡을 것 : 당신이보고 싶은 경우, 전 세계적으로는 metacall 시스템을 사용하여 호출하는 모든 슬롯은, 당신도 그렇게 할 수

#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); 
    ... 
} 
+0

'private/qobject_p.h'를 포함 할 수 없습니다. 컴파일러는 그것을 보지 않습니다. – Efog

+0

@Efog 소스에서 Qt를 완전히 설치해야합니다. 귀하의 경우 소스가 존재하지 않으므로 개인 헤더도 존재하지 않습니다. –

+0

이전 문자열 기반 신호/슬롯 연결을 사용하는 한이 기능이 작동합니다. 함수 포인터를 사용하면 QMetaCallEvent.id()에 유용한 정보가 더 이상 포함되지 않습니다. 이것은 새로운 시그널/슬롯 연결에서 뽑아 낼 수있는 최선의 방법입니다 : https://gist.github.com/webmaster128/2d4df2e46818d4e76fb7f7b8940c841a –

관련 문제