У меня есть решение, которое не является сверхчистым и не на 100% удовлетворительным, но позволяет подключать сигналы Qt к вашему собственному коду без использования компилятора MOC (у меня было точно такое же ограничение, как в вопросе, т.е. не в состоянии запустить компилятор MOC в процессе сборки моего приложения).
Чтобы иметь возможность захватывать сигналы Qt без использования MOC, я использую следующие приемы:
(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 () каждый раз, когда сигнал срабатывает, с указанным указанным method_index, полученным в ev-> id ().
Важное примечание:
Я использовал этот трюк в своем приложении в течение нескольких лет, он работает довольно хорошо, но он не очень чистый. Одним из последствий этого является то, что всякий раз, когда изменяется определение QMetaCallEvent, вам необходимо соответствующим образом редактировать свое объявление (к сожалению, оно не отображается в заголовочных файлах Qt).