PDA

View Full Version : reflection and qmetaobject



KShots
16th May 2007, 21:14
EDIT: Sorry about the mess, I was hoping the code scrollbar would keep things neater than this...

Hello all,

I'm attempting to use QMetaObject to utilize reflection concepts to connect signals in one plugin system to slots in another plugin system that match naming conventions. The basic idea is that if an input plugin has a signal like mySignal*SIGNAL_NAME*(*ARGS*), then a slot in another plugin may or may not have a slot that matches, like so: mySlot*SLOT_NAME*(*ARGS*).

I've found that during run-time, QMetaObject Qt plugins do indeed find signals and slots that are not defined in the interface (which is exactly what I was looking for)... but to make the connections, I find that I'm getting warnings on the console that say the following:
Object::connect: Use the SIGNAL macro to bind evilcpcInputVoiceSignals::evilcpcSignalActivateDVD ()

I'm using the following to make the connection:

. foreach(evilcpcInput * i, lPluginInput)
{ //For all input plugins
evilcpcInputSignals * si = i->getSignals();
const QMetaObject * imo = si->metaObject();
foreach(mi, lPluginMenuItems)
{ //For all menu item plugins
evilcpcMenuItemSlots * sl = mi->getSlots();
const QMetaObject * mimo = sl->metaObject();
for(int index(0); index < imo->methodCount(); index++)
{ //for all methods of the current input plugin
if(imo->method(index).methodType() == QMetaMethod::Signal)
{ //if this method is a signal
QString signalSignature = imo->method(index).signature();
if(signalSignature.startsWith("evilcpcSignal", Qt::CaseSensitive))
{ //It's a legitimate signature
QString signalName = signalSignature;
signalName.remove(0, strlen("evilcpcSignal"));
int position(signalName.indexOf('('));
signalName.remove(position, signalName.length() - position);
for(int index1(0); index1 < mimo->methodCount(); index1++)
{ //for all methods of the current menu item plugin
if(mimo->method(index1).methodType() == QMetaMethod::Slot)
{ //if this method is a slot
QString slotSignature = mimo->method(index1).signature();
if(slotSignature.startsWith("evilcpcSlot", Qt::CaseSensitive))
{ //It's a legitimate slot
QString slotName = slotSignature;
slotName.remove(0, strlen("evilcpcSlot"));
position = slotName.indexOf('(');
slotName.remove(position, slotName.length() - position);
if(signalName == slotName && imo->method(index).parameterTypes() == mimo->method(index1).parameterTypes())
{ //Signal matches slot, so connect them
QObject::connect(si, signalSignature.toAscii().data(), sl, slotSignature.toAscii().data());
std::cerr << "input plugin '" << i->getName().toAscii().data() << "' signal '" << signalSignature.toAscii().data() << "' connected to menu item plugin '" << mi->getName().toAscii().data() << "' slot '" << slotSignature.toAscii().data() << '\'' << std::endl;
}
}
}
}
}
}
}
}
}All my signatures look about right. How exactly should I be using connect, then?

marcel
16th May 2007, 21:19
QObject::connect(si, signalSignature.toAscii().data(), sl, slotSignature.toAscii().data());
SIGNAL and SLOT macros take a const char * as a parameter.
Therefore use:


QObject::connect(si, SIGNAL(signalSignature.toAscii().constData() ), sl, SLOT(slotSignature.toAscii().constData()) );

Please note constData() above, and not data().

Regards

KShots
16th May 2007, 21:27
If I use the SIGNAL and SLOT macros, this will not work.

I am passing a variable representing a signal / slot, rather than the signal / slot itself. Using the SIGNAL and SLOT method gives me console errors saying that signalSignature.toAscii().data() does not exist, and signalSignature.toAscii().data() does not exist.

Of course they do not exist, they are the variables, not the actual signal and slot names :(

marcel
16th May 2007, 21:29
Could you post a sample console output when using SIGNAL and SLOT?
Also, use signalSignature.toAscii().constData(), instead of data.

marcel
16th May 2007, 21:30
Anyway, signalSignature.toAscii().constData() will evaluate to a (const char*) at runtime, so I believe you should not get that message.

marcel
16th May 2007, 21:34
Actually, forget what I said before...
connect expects a const char*, not SIGNAL and SLOT, so use constData instead and it will most likely work!

Regards

wysota
16th May 2007, 21:40
SIGNAL and SLOT macros are a little hack :) Use this instead:

QObject::connect(si, (QString("2")+signalSignature).toAscii().data(),
sl, (QString("1")+slotSignature).toAscii().data());

KShots
16th May 2007, 21:49
Switched over to constData() for the QString signature conversions. I'm still getting the same problem. I've modified my connect slightly so I can check for a successful connection, and I get the following in the console now:


Object::connect: Use the SIGNAL macro to bind evilcpcInputVoiceSignals::evilcpcSignalActivateDVD ()
Failed to connect input plugin'Voice' signal 'evilcpcSignalActivateDVD()' to menu item plugin 'DVD' slot 'evilcpcSlotActivateDVD()''

... and using the SIGNAL macro, I get the following:
Object::connect: No such signal evilcpcInputVoiceSignals::signalSignature.toAscii( ).constData()
Failed to connect input plugin'Voice' signal 'evilcpcSignalActivateDVD()' to menu item plugin 'DVD' slot 'evilcpcSlotActivateDVD()''

KShots
16th May 2007, 21:53
SIGNAL and SLOT macros are a little hack :) Use this instead:

QObject::connect(si, (QString("2")+signalSignature).toAscii().data(),
sl, (QString("1")+slotSignature).toAscii().data());Thanks, that worked perfectly :)