PDA

View Full Version : array of slots?



vonCZ
15th July 2007, 12:41
this is a simplified version of my problem: I have 2 sliders that send information to another class/object:


// .h file
QSlider *zXag[2];


// .cpp file

zXag[0] = new QSlider(Qt::Vertical);
zXag[1] = new QSlider(Qt::Vertical);

My problem is with the connect. I want to do something like this:



connect(zXag[0], SIGNAL(valueChanged(int)), coin3dWidget, SLOT(setVertExag_0(int)));
connect(zXag[1], SIGNAL(valueChanged(int)), coin3dWidget, SLOT(setVertExag_1(int)));


which works fine. But instead of 2 SLOT functions defined like above, I want something like:

setVertExag[0](int)
setVertExag[1](int)

In other words, just as I've an array of 2 slider objects, I'd like an array of 2 slot functions. I know you cannot make arrays of functions in C++, but hopefully you can at least see what I'm trying to do here and can suggest a solution. Below is the actual function that generates my sliders (and connects), in case this helps explain:



//function call
for(int a=0; a<Total_Num_Sliders; a++)
{
mkZXag(a);
}

//function
void Window::mkZXag(int compNUM)
{

zXag[compNUM] = new QSlider(Qt::Vertical);
zXag[compNUM]->setSingleStep(1);
zXag[compNUM]->setTickInterval(10);
zXag[compNUM]->setTickPosition(QSlider::TicksRight);

connect(zXag[compNUM], SIGNAL(valueChanged(int)), coinWidget, SLOT(setVExag/*???*/(int)));

}

marcel
15th July 2007, 13:05
Well, I think you can use QMetaObject (http://doc.trolltech.com/latest/qmetaobject.html) to accomplish this. But you will need a very strict slot naming convention.
You will have to iterate through all the methods of the receiving object( using QMetaObject::methodCount (http://doc.trolltech.com/latest/qmetaobject.html#methodCount) and QMetaObject::method(int) (http://doc.trolltech.com/latest/qmetaobject.html#method) ) and for each method that has the type QMetaMethod::Slot compare it's signature with a QString = "setVertExag_" + sliderIndex.
If they are equal(which means you have defined that slot), then just construct the slot name( which has to be const char*) and pass it to connect.

Another solution is to make an array of slot names, but you will have to update it each time you add a new slot.


Regards

vonCZ
15th July 2007, 14:12
Another solution is to make an array of slot names, but you will have to update it each time you add a new slot.

thanks Marcel. I've already got a class designed to manage this sort of thing, so it might be the easiest solution. I know this should be straight-forward, but I tried the following and it didn't work:




char *zXagSlotName[] =
{
"na",
"na",
"set_zXag02(int value)",
"set_zXag03(int value)",
"set_zXag04(int value)",
"set_zXag05(int value)",
"set_zXag06(int value)",
};

char *get_zXagSlotNames(int value) { return zXagSlotName[value]; }


but when I do this:



connect(zXag[indexNUM], SIGNAL(valueChanged(int)), coinWidget, SLOT(getzXagSlotName(indexNUM)));

I get the following (not surprising) message:
Qbject::connect: No such slot CoinWidget::getzXagSlotName(compNUM)

what should I put here *

SLOT(*)

or Is this what you had in mind?

marcel
15th July 2007, 15:54
It is because you use the SLOT macro. It is used to build a function signature(const char*).
Since the array you already have is of const char*, you can pass directly an element of that array.
Like:

connect(zXag[indexNUM], SIGNAL(valueChanged(int)), coinWidget, zXagSlotName[indexNUM]); (http://doc.trolltech.com/latest/connect%28zxag%5Bindexnum%5D,%20signal%28valuechan ged%28int%29%29,%20coinwidget,%20getzxagslotname%2 8indexnum%29%29;.html)

Also be careful for index out of bounds errors on that array.

Regards

vonCZ
15th July 2007, 16:55
thanx, but it still doesn't work; compiles, but I get the following message run-time:


Object::connect: Use the SLOT or SIGNAL macro to connect CoinWidget::set_zXag02(int value)

at least now it sees what I want to connect to, CoinWidget::set_zXag02(int value)... but still instructing me to use the SLOT macro.

marcel
15th July 2007, 17:08
Yeah, sorry about that :).
Change the array from char* to const char* and prepend to every slot name "1";
Like this:



const char* zXagSlotName[] =
{
"na",
"na",
"1set_zXag02(int value)",
"1set_zXag03(int value)",
"1set_zXag04(int value)",
"1set_zXag05(int value)",
"1set_zXag06(int value)",
};


It should work now with the connect statement I have presented you earlier( just tested it here).


Regards

vonCZ
15th July 2007, 18:01
excellent, Marcel, thanks. One last correction though: I had to drop "value" from the parameter list like so:


const char *zXagSlotName[] =
{
"na",
"na",
"1set_zXag02(int)",
"1set_zXag03(int)",
"1set_zXag04(int)",
"1set_zXag05(int)",
"1set_zXag06(int)",
};

you probably copy/pasted my earlier mistake. I must say: Qt Centre Forum rocks.:D

marcel
15th July 2007, 18:07
excellent, Marcel, thanks. One last correction though: I had to drop "value" from the parameter list like so:


const char *zXagSlotName[] =
{
"na",
"na",
"1set_zXag02(int)",
"1set_zXag03(int)",
"1set_zXag04(int)",
"1set_zXag05(int)",
"1set_zXag06(int)",
};you probably copy/pasted my earlier mistake. I must say: Qt Centre Forum rocks.:D

Yes, I copied it from your post.
I did a simpler test, with only one slot.
Nevertheless, it is good it works.

Note: if you want to do the same thing with signals, then you must prepend "2" to the signal name. But you can find out more by just looking at the SIGNAL/SLOT macro implementations in the Qt sources

Regards.

wysota
16th July 2007, 00:56
Why not just use a signal mapper? Do you really need an array of methods? How about just having a single method that takes two arguments instead of one? That would be a much cleaner design and you wouldn't have to dive into low-level metaobject info (and think about how it improves code maintenance!).

rajesh
16th July 2007, 07:09
emit a user define signal(say sliderChange(int)) on slider's value change, then
write in parent class:
connect(Window, SIGNAL(sliderChange(int)), coin3dWidget, SLOT(setVertExag(int)));

in setVertExag(int i)
{
QSlider *slider = qobject_cast<QSlider *>(sender());
// here you will get the address of slider who emited the signal. and you can access that object data.

}
the above code is incomplete code. this is just hint.
or you use QSignalMapper (http://www.qtcentre.org/forum/qsignalmapper.html#QSignalMapper)

vonCZ
19th July 2007, 08:16
Why not just use a signal mapper? Do you really need an array of methods?

good point. I *think* i'll need multiple functions (that take input from the Sliders) in the Coin3d part of the app, but I should be able to call those specific functions using SigMap or Rajesh's suggestion....