我有一个解决方案,它不是超级干净,也不是 100% 令人满意,但它允许将 Qt 信号连接到您自己的代码,而无需使用 MOC 编译器(我的约束与问题中的完全相同,即无法在我的应用程序的构建过程中运行 MOC 编译器)。
为了能够在不使用 MOC 的情况下捕获 Qt 信号,我使用了以下技巧:
(1) 获取 QMetaCallEvent 的定义(从 复制):
在 Qt 5.x 中,您将拥有如下内容:
class QMetaCallEvent : public QEvent {
public:
inline int id() const {
return method_offset_ + method_relative_;
}
virtual void placeMetaCall(QObject *object);
private:
QMetaCallEvent();
void* slotObj_;
const QObject *sender_;
int signalId_;
int nargs_;
int *types_;
void **args_;
void *semaphore_;
void *callFunction_;
ushort method_offset_;
ushort method_relative_;
};
(2) 在需要捕获 Qt 信号的小部件类中,您将继承自 Qt 小部件(例如 QButton),并定义以下函数:
// Inspired by QObject::connect() in src/corelib/kernel/qobject.cpp
bool connect_sender(
const QObject* sender, const char* signal, int method_index
) {
// We need to generate MetaCall events (since QObject::event()
// is the only virtual function we can overload)
// (note that the other connection types do not generate events).
Qt::ConnectionType type = Qt::QueuedConnection ;
if(sender == 0 || signal == 0) {
std::cerr << "null sender or signal" << std::endl ;
return false ;
}
QByteArray tmp_signal_name;
const QMetaObject *smeta = sender->metaObject();
++signal; //skip code
int signal_index = smeta->indexOfSignal(signal);
if (signal_index < 0) {
// check for normalized signatures
tmp_signal_name =
QMetaObject::normalizedSignature(signal).prepend(*(signal - 1));
signal = tmp_signal_name.constData() + 1;
signal_index = smeta->indexOfSignal(signal);
if (signal_index < 0) {
std::cerr << "Signal \'" << signal << "\' not found"
<< std::endl ;
return false;
}
}
int *types = 0;
QMetaObject::connect(
sender, signal_index, this, method_index, type, types
) ;
return true ;
}
(3)重载event()函数:
bool event(QEvent* e) {
if(e->type() == QEvent::MetaCall) {
QMetaCallEvent* ev = static_cast<QMetaCallEvent*>(e);
switch(ev->id()) {
// insert your handling code here
}
return true;
}
return QObject::event(e) ;
}
现在,如果你调用 connect_sender(qobject, signal_name, method_index),这个
每次触发信号时都会调用 event(),并在 ev->id() 中检索指定的 method_index。
重要提示:
几年来我一直在我的应用程序中使用这个技巧,效果很好,但不是很干净。后果之一是,每当 QMetaCallEvent 的定义发生变化时,您都需要相应地编辑您的声明(不幸的是,它没有在 Qt 的头文件中公开)。