I have a solution, that is not super-clean and not 100% satisfactory, but that allows to connect Qt signals to your own code without having to use the MOC compiler (I had exactly the same constraint as in the question, i.e. not able to run the MOC compiler in the building process of my application).
To be able to capture Qt signals without using MOC, I am using the following tricks:
(1) get the definition of QMetaCallEvent (copy it from ):
In Qt 5.x, you will have something like:
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) In your widget class that needs to capture Qt signals, you will inherit from a Qt widget (say QButton), and define the following function:
// 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) overload the event() function:
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) ;
}
Now, if you call connect_sender(qobject, signal_name, method_index), this
will call event() each time the signal is fired, with the specified method_index retrieved in ev->id().
Important note:
I have been using this trick in my application for several years, it works quite well, but it is not very clean. One of the consequences is that whenever the definition of QMetaCallEvent changes, you need to edit your declaration accordingly (unfortunately it is not exposed in the header files of Qt).
moc
tool is the main reason I haven't jumped onto the Qt bandwagon. – Avermoc
is really only a problem until you actually use it. I used to balk at the idea of an extra preprocessing step, but once I started using Qt instead of just thinking about it,moc
ceased to be a nuisance. Especially if you use QMake,moc
is almost invisible in practice. – Weeny