PDA

View Full Version : dynamcly allocated buttons



MarkoSan
10th December 2007, 18:05
Hi to all!

I've dynamically created buttons (the number of them is NOT known at compile time, but at runtime). It works ok, buttons are shown as I wanted. But now, I need to connect every button's signal clicked() to some slot function. How do I provide slot functions at runtime?? :confused:

MarkoSan
10th December 2007, 18:13
It look like I did it on my own. :D But it does not work. Is it allowed to setup slot from one object and then call slot from different object?

I got to gdb and i get following message:
warning: Object::connect: No such slot COperationWIndow::m_pMerchandizeBrowser->fillMerchandize(iIndex)

Why this does not work?

wysota
10th December 2007, 18:18
How do I provide slot functions at runtime?? :confused:
I don't think you can add methods to classes at runtime in C++ :)


Is it allowed to setup slot from one object and then call slot from different object?

If you think about something like this:

connect(object1, SIGNAL(sig()), object2, SLOT(sl())); // "this" is neither object1 nor object2
then yes.

MarkoSan
10th December 2007, 18:21
Well, if I got it right, then:
m_MerchandizeSelectorButtons.at(iIndex)->connect(m_pButtonMerchandizeConfirmer,
SIGNAL(clicked()),
this. SLOT(m_pMerchandizeBrowser->fillMerchandize(iIndex)));


then second "this" is the name of "target" object?

jpn
10th December 2007, 18:24
You can't put a statement into SLOT() macro like that. Take a look at QButtonGroup or QSignalMapper.

MarkoSan
10th December 2007, 18:29
QSIgnalMapper? I hate it, I've never understood it, I've read the docs about QSignalMapper but it is my humble opinion these docs are not written at the best ...

jpn
10th December 2007, 18:43
QSIgnalMapper? I hate it, I've never understood it, I've read the docs about QSignalMapper but it is my humble opinion these docs are not written at the best ...
To be direct and honest, you should start with reading the article about signals and slots (http://doc.trolltech.com/latest/signalsandslots.html). It's the very basic principle of signals and slots that the SLOT() macro takes a slot name plus optional parameter types, without parameter names, and nothing more. Once you understand how signals and slots work, it should be straightforward to understand QSignalMapper docs. Besides, QButtonGroup should be even easier to use...

MarkoSan
10th December 2007, 18:47
Ok, but I simply must overcome this QSignalMapper since it is very useful. :rolleyes: I understand signal/slots feature, but this QSignalMapper is giving me headache. Now let me dig into it ... :D

MarkoSan
10th December 2007, 23:38
Does every button in a QList <QPushButton*> need its own QSIgnalMapper?

jacek
11th December 2007, 01:00
Does every button in a QList <QPushButton*> need its own QSIgnalMapper?
No, you need only one signal mapper for the whole list.

In Qt docs you can find such example:

...
for (int i = 0; i < texts.size(); ++i) {
QPushButton *button = new QPushButton(texts[i]);
connect(button, SIGNAL(clicked()), signalMapper, SLOT(map()));
signalMapper->setMapping(button, texts[i]);
...
}

connect(signalMapper, SIGNAL(mapped(const QString &)),
this, SIGNAL(clicked(const QString &)));
...

The setMapping() line tells the signal mapper that whenever the particular button invokes map(), the signal mapper should emit mapped(const QString &) signal with given parameter. So in this case you can replace all clicked() signals coming from different buttons with a single mapped( const QString & ) signal that comes from the signal mapper (of course parameter value depends on which button sent the original signal).

You can have a mapped() signal also with integer, QObject * or QWidget * parameter --- you just have to use the other setMapping() method variants instead.

In your case you can use QButtonGroup as jpn has suggested. Basically it's like a QSignalMapper but crafted especially for buttons.

MarkoSan
11th December 2007, 01:10
I would stick to QSignalMapper because I simply must overcome this topic. So, let me dig into it and try to reprogramm the example...

Well, I've done this:
m_MerchandizeSelectorButtons.at(iIndex)->connect(m_MerchandizeSelectorButtons.at(iIndex),
SIGNAL(clicked()),
m_pMerchandizeSelectorButtonSignalMapper,
SLOT(map()));

What should I now put into map() slot? Call to other's object slot?

wysota
11th December 2007, 01:23
Do you know why you were suggested to use a signal mapper or do you just follow the advice blindly without trying to understand the problem first?

MarkoSan
11th December 2007, 01:27
I know why i was suggested to use signal mapper. That is because I cannot send a slot to other object, or am I wrong again??

wysota
11th December 2007, 01:35
That is because I cannot send a slot to other object, or am I wrong again??

Yes, you are right - you are wrong again.

The signal mapper is used so that you can pass an integer argument to a slot connected to a signal that doesn't emit any arguments. If you just want to connect a signal to a slot, you don't need a signal mapper:


for(int i=0;i<10;i++){
QPushButton *b = new QPushButton(this);
((QHBoxLayout*)layout())->addWidget(b);
connect(b, SIGNAL(clicked()), this, SLOT(fillMerchandize())); // see? no mapper
}

Compare your original code and this one. As you see fillMerchandize() doesn't take an int argument as you'd probably like it to. To get that index you have two solutions:
1. inside fillMerchandize() use QObject::sender() to compare the pointer of the object that sent the signal to each and every pointer stored in your list to determine the index of the list occupied by the button you want.

or

2. use a QSignalMapper as already advised (which basically does the same).

Note, that if you don't need the index (number) of the list but only a pointer to the button, you don't need the signal mapper - you can cast sender() to your button class and use the pointer. Just use a smart casting technique like qobject_cast.

MarkoSan
11th December 2007, 10:00
Guys, this is what I've done:
for(iIndex=0; iIndex<m_MerchandizeGroupsNames.size(); iIndex++)
{
// creates new button
//QString buttonText=m_MerchandizeGroupsNames.at(iIndex); // gets button text
QPushButton* pTempButton=new QPushButton(m_MerchandizeGroupsNames.at(iIndex), this);
Q_CHECK_PTR(pTempButton);
// adds button to list
m_MerchandizeSelectorButtons.append(pTempButton);
m_cPalette=m_MerchandizeSelectorButtons.at(iIndex)->palette(); // gets current pallete of button
m_cPalette.setColor(QPalette::Button, Qt::red); // sets up new palette componenet
m_cPalette.setColor(QPalette::ButtonText, Qt::black); // sets up new palette componenet
m_MerchandizeSelectorButtons.at(iIndex)->setPalette(m_cPalette); // sets new pallete
m_MerchandizeSelectorButtons.at(iIndex)->setFont(merchandizeButtonFont); // sets font
// connects buttons's slick to merchandize browser slot for filling pictures of selected group
/*
m_MerchandizeSelectorButtons.at(iIndex)->connect(m_pButtonMerchandizeConfirmer,
SIGNAL(clicked()),
m_pMerchandizeBrowser,
SLOT(m_pMerchandizeBrowser->fillMerchandize(iIndex)));
*/
m_MerchandizeSelectorButtons.at(iIndex)->connect(m_MerchandizeSelectorButtons.at(iIndex),
SIGNAL(clicked()),
m_pMerchandizeSelectorButtonSignalMapper,
SLOT(map()));
m_pMerchandizeSelectorButtonSignalMapper->setMapping(m_MerchandizeSelectorButtons.at(iIndex) , iIndex);
// adds newly created button to layout
m_pMerchandizeSelectorButtonsLayout->addWidget(m_MerchandizeSelectorButtons.at(iIndex)) ;
//delete pTempButton; // deletes temp button
}

/*
connect(m_pMerchandizeSelectorButtonSignalMapper, SIGNAL(mapped(qint16 iIndex)),
m_pMerchandizeBrowser, SIGNAL(clicked(qint16 iIndex)));
*/
connect(m_pMerchandizeSelectorButtonSignalMapper, SIGNAL(mapped(qint16 iIndex)),
this, SIGNAL(clicked(qint16 iIndex)));


I still get gdb warnings about there is not signalmapper::map slot. I might be stupid or something, but please help me!!

jpn
11th December 2007, 10:12
connect(m_pMerchandizeSelectorButtonSignalMapper, SIGNAL(mapped(qint16 iIndex)),
this, SIGNAL(clicked(qint16 iIndex)));


Go take a look at QSignalMapper docs. Which signals does it offer? Does it offer a signal with qint16 parameter? Notice that qint16 is not same type as int.

wysota
11th December 2007, 10:50
And we don't pass variable names in SIGNAL and SLOT signatures.

MarkoSan
13th January 2008, 12:47
I've finally rewritten the code as follows:
for(iIndex=0; iIndex<m_MerchandizeGroupsNames.size(); iIndex++)
{
// creates new button
//QString buttonText=m_MerchandizeGroupsNames.at(iIndex); // gets button text
QPushButton* pTempButton=new QPushButton(m_MerchandizeGroupsNames.at(iIndex), this);
Q_CHECK_PTR(pTempButton);
// adds button to list
m_MerchandizeSelectorButtons.append(pTempButton);
m_cPalette=m_MerchandizeSelectorButtons.at(iIndex)->palette(); // gets current pallete of button
m_cPalette.setColor(QPalette::Button, Qt::red); // sets up new palette componenet
m_cPalette.setColor(QPalette::ButtonText, Qt::black); // sets up new palette componenet
m_MerchandizeSelectorButtons.at(iIndex)->setPalette(m_cPalette); // sets new pallete
m_MerchandizeSelectorButtons.at(iIndex)->setFont(merchandizeButtonFont); // sets font
// connects buttons's slick to merchandize browser slot for filling pictures of selected group
/*
m_MerchandizeSelectorButtons.at(iIndex)->connect(m_MerchandizeSelectorButtons.at(iIndex),
SIGNAL(clicked()),
this,
SLOT(setGroup()));
m_pMerchandizeSelectorButtonSignalMapper->setMapping(m_MerchandizeSelectorButtons.at(iIndex) , iIndex);
*/
connect(pTempButton, SIGNAL(clicked()),
m_pMerchandizeSelectorButtonSignalMapper, SLOT(map())); // connects button to signal mapper
m_pMerchandizeSelectorButtonSignalMapper->setMapping(pTempButton, (int)iIndex); // sets mapping
// adds newly created button to layout
m_pMerchandizeSelectorButtonsLayout->addWidget(m_MerchandizeSelectorButtons.at(iIndex)) ;
//delete pTempButton; // deletes temp button
} // for
connect(m_pMerchandizeSelectorButtonSignalMapper, SIGNAL(mapped(const int&)),
this, SIGNAL(clicked(const int&))); // connects signal mapper to buttonNow, how do I "catch" SIGNAL "clicked"? I've declared it in .h file with:
signals:
void clicked(const int &iIndex); // pushbutton slotand If I try to write appropriate code for it in the .cpp file, I get following error:
Severity and Description Path Resource Location Creation Time Id
./debug\moc_COperationWIndow.o In function `ZN16COperationWIndow7clickedERKi': eROSystem line 0 1200210789421 2773
C:/Documents and Settings/markofr/workspace/eROSystem/debug/moc_COperationWIndow.cpp multiple definition of `COperationWIndow::clicked(int const&)' eROSystem line 85 1200210789421 2774
first defined here eROSystem COperationWIndow.cpp line 348 1200210789421 2775
make: *** [debug] Error 2 eROSystem line 0 1200210789421 2777
make[1]: *** [debug\eROSystem.exe] Error 1 eROSystem line 0 1200210789421 2776Why??

Gopala Krishna
13th January 2008, 15:16
I've finally rewritten the code as follows:[code] {snip}
Why??

Because you can only implement the code for slots not signals :) Make "clicked(const int&))" this a slot rather than a signal.

Please make sure you know the basics of signals and slots first. :)

MarkoSan
13th January 2008, 15:54
I've read signal/slot mechanism, but I saw nowhere in the docs slot can take parameters, so it can or not???

Gopala Krishna
13th January 2008, 16:11
I've read signal/slot mechanism, but I saw nowhere in the docs slot can take parameters, so it can or not???

Yup it can. Infact a slot is a normal function.

MarkoSan
13th January 2008, 16:27
Ok, but I still do not understand this: In my code, as far as I understood the example in the docs, every time the button will be pressed, the signal clicked(int) will be emited. How do I catch this signal??

Why the hell this code does not work:
for(quint16 iIndex=0; iIndex<m_MerchandizeGroupsNames.size(); iIndex++)
{
// creates new button
//QString buttonText=m_MerchandizeGroupsNames.at(iIndex); // gets button text
QPushButton* pTempButton=new QPushButton(m_MerchandizeGroupsNames.at(iIndex), this);
Q_CHECK_PTR(pTempButton);
pTempButton->setFocusPolicy(Qt::NoFocus); // sets no focus
// adds button to list
m_MerchandizeSelectorButtons.append(pTempButton);
m_cPalette=m_MerchandizeSelectorButtons.at(iIndex)->palette(); // gets current pallete of button
m_cPalette.setColor(QPalette::Button, Qt::red); // sets up new palette componenet
m_cPalette.setColor(QPalette::ButtonText, Qt::black); // sets up new palette componenet
m_MerchandizeSelectorButtons.at(iIndex)->setPalette(m_cPalette); // sets new pallete
m_MerchandizeSelectorButtons.at(iIndex)->setFont(merchandizeButtonFont); // sets font
// connects buttons's slick to merchandize browser slot for filling pictures of selected group
/*
m_MerchandizeSelectorButtons.at(iIndex)->connect(m_MerchandizeSelectorButtons.at(iIndex),
SIGNAL(clicked()),
this,
SLOT(setGroup()));
m_pMerchandizeSelectorButtonSignalMapper->setMapping(m_MerchandizeSelectorButtons.at(iIndex) , iIndex);
*/
connect(pTempButton, SIGNAL(clicked()),
m_pMerchandizeSelectorButtonSignalMapper, SLOT(map())); // connects button to signal mapper
m_pMerchandizeSelectorButtonSignalMapper->setMapping(pTempButton, (int)iIndex); // sets mapping
// adds newly created button to layout
m_pMerchandizeSelectorButtonsLayout->addWidget(m_MerchandizeSelectorButtons.at(iIndex)) ;
//delete pTempButton; // deletes temp button
} // for

connect(m_pMerchandizeSelectorButtonSignalMapper, SIGNAL(mapped(const int&)),
this, SIGNAL(clicked(const int&))); // connects signal mapper to button
connect(m_pMerchandizeSelectorButtonSignalMapper, SIGNAL(clicked(const int&)),
this, SLOT(filterMerchandize(const int&))); // connects emited signal to slotHere is the needed slot filterMerchanize:
/* !
* slot for filtering merchandize pictures
*/
void filterMerchandize(const int &iMerchandizeGroup); and here is its current implementation:
void COperationWIndow::filterMerchandize(const int &iMerchandizeGroup)
{
qDebug() << iMerchandizeGroup; // debug
}In the debug mode, the qebug() statement is not called. Why???? I am losing battle and nerves here ....

MarkoSan
13th January 2008, 23:06
No one knows??

jacek
13th January 2008, 23:13
No one knows??
On Sunday evening?

What do connect statements return? Is there any reason for using const int & instead of int?

MarkoSan
13th January 2008, 23:17
On Sunday evening?

What do connect statements return? Is there any reason for using const int & instead of int?

Ok, Sunday evening it is, I know. :D But I've been struggeling with this shit QSignalMapper for a while now and I am losing patience, nerves and good will to do Qt. :D The only reason for using const int& in the code is that it was like this in example. I have been learning from example that are in the docs of QSignalMapper.

P.S.: for the code there is no weekend, just working and faulty days. :p:D

jacek
13th January 2008, 23:42
So what are the return values for connect statements after you change const int & to int?

MarkoSan
13th January 2008, 23:53
Honeslty, I have no clue, because I do not get it why are in example const int&. Where is the catch?

jacek
14th January 2008, 00:17
I do not get it why are in example const int&.
Where? Could you post a link?

MarkoSan
14th January 2008, 01:08
http://doc.trolltech.com/4.3/qsignalmapper.html

I am sorry, there are QString & and not int &. I thought it is the same but now I will try ordinary int in my code.

I've changed all const int& to ordinary int, same shit. While in debug mode, the program does not stop on breakpoint set in slot fillMerchandize. What is going on???!!

It woooooooooorks!!!! At the second connect, the parent parameter is THIS - self pointer (QWidget) and not instance made by QSignalMapper. Jacek, thank you for hints!!!!