PDA

View Full Version : Slot gets called twice



greatgatsby
20th August 2009, 12:31
Hi, I'm a 10+ year C++ programmer but n3wb to Qt...

I've successfully installed the Qt 4.5.2 SDK (MinGW g++) but, since I primarily use VC++, also installed the VS2008 plugin and built the Qt 4.5.2 sources for VC++ in a separate directory. After fixing some Environmental Values/Paths issues between the 2 Qt now works fine under both compilers/IDEs.

I've made some simple test programs to try out Qt, but noticed that my custom slots always gets called twice for a single signal - and it happens in both IDEs

In QtDesigner I add a signal/slot to a QPushButton where the Sender is the QPushButton (signal is clicked()) and the Receiver a custom slot (called on_pbAdd_clicked()) on my form class derived form QDialog.

Since QtDesigner does not automatically generate the slots anymore, I've declared the slots like this:


class Dialog : public QDialog
{
Q_OBJECT
public:
Dialog(QWidget *parent = 0, Qt::WFlags flags = 0);
~Dialog();
private:
Ui::DialogClass ui;
public slots:
virtual void on_pbAdd_clicked(void);
virtual void on_pbRemove_clicked(void);
};


The slot is implemented like this:


void Dialog::on_pbAdd_clicked(void)
{
if(ui.leEdit->text().length() > 0) {
...
}
}


I've tried to debug the issue: When the button is clicked one of the void QMetaObject::activate(...) functions in qobject.cpp gets called, specifically:


void QMetaObject::activate(QObject *sender, int from_signal_index, int to_signal_index, void **argv)
{
....
int count = connectionLists->at(signal).count();
for (int i = 0; i < count; ++i) {
const QObjectPrivate::Connection *c = &connectionLists->at(signal)[i];
...
receiver->qt_metacall(QMetaObject::InvokeMetaMethod, method, argv ? argv : empty_argv);
...
}
...
}

The count variable is set to 2 from the call to connectionLists->at(signal).count();. This means the next for loopis executed twice - which causes the slot to be called twice in the receiver->qt_metacall() function call. This resolves to a call to Dialog::qt_metacall(...) that was generated by the moc, which looks like this:


int Dialog::qt_metacall(QMetaObject::Call _c, int _id, void **_a)
{
_id = QDialog::qt_metacall(_c, _id, _a);
if (_id < 0)
return _id;
if (_c == QMetaObject::InvokeMetaMethod) {
switch (_id) {
case 0: on_pbAdd_clicked(); break;
case 1: on_pbRemove_clicked(); break;
default: ;
}
_id -= 2;
}
return _id;
}


The case 0 in the switch statement then calls my on_pbAdd_clicked() slot - which seems perfect. So everything seems to work fine, with the exception of that connectionLists->at(signal).count(); value that is returned, which result in the slot being called twice!

I am not yet familiar with the Qt code-base, so can anybody maybe help and maybe shed some light on this? How does one overcome this?

Thanx

vieraci
20th August 2009, 12:45
If you're using the GUI designer you don't need to manually declare slots, you can get designer to create them for you from the object's context menu. (goto->slot)

Maybe delete your slots and re-create them with designer and see if you still have a problem.

spirit
20th August 2009, 12:47
your slot already connected in ui-file using QMetaObject::connectSlotsByName.
so, you should rename your slots or remove connections in designer.

greatgatsby
20th August 2009, 13:05
thanks for your very quick response. But I am not sure i understand how to do this....

I don't think I have this context menu (goto->slot) in my 4.5.2 Designer (not in the VS Plugin and also not in 4.5.2 QtCreator either).

In my Designer if I view the Signals end slots editor I do not see any context menus [right-clcicking, from ny menu, etc].

In fact, if I look at http://www.qtcentre.org/forum/faq.php?faq=qt_designer_category#faq_qt_designer_s ignals_inqt4:


How can I add a custom slot in Qt4 Designer? In short - you can't. Beginning with Qt4.0 Qt Designer seized to be an all-purpose development environment and became strictly a GUI Designer...etc

Can you be more specific...

Thankx

spirit
20th August 2009, 13:13
you wrote


In QtDesigner I add a signal/slot to a QPushButton where the Sender is the QPushButton (signal is clicked()) and the Receiver a custom slot (called on_pbAdd_clicked()) on my form class derived form QDialog.

that means, that "on_pbAdd_clicked" default slot according to this (http://doc.trolltech.com/4.5/qmetaobject.html#connectSlotsByName), in ui-file you can find such call QMetaObject::connectSlotsByName (this will create first connection), than you have declared slot on_pbAdd_clicked and probably connected it in ctor (I'm not sure) in that case you created the second connection.

greatgatsby
20th August 2009, 13:31
@spirit - thanks for your very prompt reply.

It seems to have done the trick!

But - just to make sure I understand: Does this imply that if you follow the the slot function naming convention of on_<objectname>_<signalname>(), then it is not necessary to define signal/slot combinations in the signal/slot editor of Designer since Qt can figure out which custom slot to call (which - as you imply - is done in the QMetaObject::connectSlotsByName() function)?

I've noticed that removing the connections in the signal/slot editor of Designer also removes the connections being generated by the moc previously:


void setupUi(QDialog *DialogClass)
{
...
QObject::connect(pbAdd, SIGNAL(clicked()), DialogClass, SLOT(on_pbAdd_clicked()));
QObject::connect(pbRemove, SIGNAL(clicked()), DialogClass, SLOT(on_pbRemove_clicked()));
...
}

Is this on_<objectname>_<signalname>() convention a kind of
short-hand for custom
on the fly slot generation as an alternative to the Designer route?

Thanx again [can see I still have lots to learn about Qt!]

spirit
20th August 2009, 13:34
all what you need it's to create a slot, but don't connect it, because it's already connected in ui. :)

greatgatsby
20th August 2009, 15:11
Got it!

Thanks a stack @spirit!