什么是QMetaCallEvent以及如何访问其详细信息?

Raf*_*afe 4 meta events qt filter qevent

我有一个事件过滤器,当我点击展开/折叠我得到的树枝时,我注意到了QEvent::MetaCall.我正在考虑使用它来滚动我自己的展开/折叠代码,但我不知道如何获取任何信息,例如项目的索引.

这个MetaCall事件类型有什么可用的吗?

我发现有人在另一个网站上问过同样的问题,但没有答案,请点击此处:http: //www.qtcentre.org/threads/37525-How-to-filter-QEvent-MetaCall

这个事件通常用于什么?

Rei*_*ica 8

最大的问题是:你究竟想做什么?接受这些活动的Qt课程是什么?就我而言,你正试图以艰难的方式做事,所以为什么要这么做呢?

QMetaCallEvent是代表一个时隙呼叫每当事件排队的连接被用来调用的槽.这可能是由于连接到插槽的信号触发,或由于使用QMetaObject::invokeQMetaObject::invokeMethod.排队的连接位是重要的部分!默认情况下,对同一线程中的对象之间的调用使用排队连接,因为它们具有事件队列管理开销,除非以下两个条件中的任何一个成立:

  1. 您提供Qt::QueuedConnection给说法QObject::connectQMetaObject::invoke[Method],

  2. 接收对象thread()与呼叫发起的线程不同 - 在呼叫时.

QMetaCallEvent事件类携带调用一个时隙所需的信息.它包含发送方QObject及其信号id(如果调用来自信号槽连接),以及目标槽标识符,以及需要传递到插槽的参数.

因此,您可以检查被调用的插槽是否是您要拦截的插槽,以及传递给它的参数.例如,如果您使用单个int参数调用插槽,*reinterpret_cast<int*>(metaCallEvent->args()[1])则会为您提供该整数的值.第零个参数用于返回值(如果有),因此参数使用基数1建立索引.

免责声明由于QMetaCallEvent该类是Qt实现的内部,因此您将应用程序的二进制文件与特定的Qt版本完全绑定(整个major.minor版本),并且您将失去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;
}
Run Code Online (Sandbox Code Playgroud)

如果要全局查看使用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);
  ...
}
Run Code Online (Sandbox Code Playgroud)