Connect signals with arguments
-
wrote on 4 May 2021, 10:09 last edited by
Hello,
I am trying to do a small videogame with QT for school.
The main goal is to fight ennemies and go the further.
When you defite a enemy, you can get item carried by him, and that is my point.
To get the item, I press a button which is connected to a function that add item to hero's backpack.
I have to give the item in argument, that why I defined a special class for my button, ItemButton, which extends QPushButton.
Here is itembutton.cppvoid ItemButton::emitclicked(Item new_item){ emit clicked(); }
and itembutton.h
#ifndef ITEMBUTTON_H #define ITEMBUTTON_H #include <QPushButton> #include "item.h" class ItemButton : public QPushButton { public: signals: void emitclicked(Item new_item); }; #endif // ITEMBUTTON_H
When i connect my button to this function by
connect(button, SIGNAL(emitclicked(actual_ennemy->getItems().getItem(i))), this, SLOT(new_item(actual_ennemy->getItems().getItem(i))));
i get the following error :
QObject::connect: No such signal QPushButton::emitclicked(actual_ennemy->getItems().getItem(i)) in ..\Programmation\mainwindow.cpp:501
So QT think i call a signal from QPushButton. But button is a ItemButton (ItemButton *button;)
So, how can i connect to my signal defined in ItemButton ? Thanks -
Hello,
I am trying to do a small videogame with QT for school.
The main goal is to fight ennemies and go the further.
When you defite a enemy, you can get item carried by him, and that is my point.
To get the item, I press a button which is connected to a function that add item to hero's backpack.
I have to give the item in argument, that why I defined a special class for my button, ItemButton, which extends QPushButton.
Here is itembutton.cppvoid ItemButton::emitclicked(Item new_item){ emit clicked(); }
and itembutton.h
#ifndef ITEMBUTTON_H #define ITEMBUTTON_H #include <QPushButton> #include "item.h" class ItemButton : public QPushButton { public: signals: void emitclicked(Item new_item); }; #endif // ITEMBUTTON_H
When i connect my button to this function by
connect(button, SIGNAL(emitclicked(actual_ennemy->getItems().getItem(i))), this, SLOT(new_item(actual_ennemy->getItems().getItem(i))));
i get the following error :
QObject::connect: No such signal QPushButton::emitclicked(actual_ennemy->getItems().getItem(i)) in ..\Programmation\mainwindow.cpp:501
So QT think i call a signal from QPushButton. But button is a ItemButton (ItemButton *button;)
So, how can i connect to my signal defined in ItemButton ? Thanks@Lc44bzh said in Connect signals with arguments:
emitclicked(actual_ennemy->getItems().getItem(i))
You can't pass parameters to signal when you connect. Parameters are passed to the signal when the signal is emitted. Same applies to slots: those get their parameters from the signal.
Please read https://doc.qt.io/qt-5/signalsandslots.html There are also examples. -
There are several issues with your code:
- signal cannot have implementation (you can't have
emitclicked()
body in cpp file, only declaration in header) connect
statement only connects signals and slot, you cannot provide any actual data there likeactual_ennemy->getItems().getItem(i))
. The only stuff you should provide there are argument types. Even better: use new functor-based connection syntax https://doc.qt.io/qt-5/signalsandslots-syntaxes.html- connect is called only once, when a connection is made - so it has no idea what data will be sent through it later
So QT think i call a signal from QPushButton
Not quite, your code is simply wrong. Here is how to fix it:
- connect your button's
clicked()
signal (it can be a normal QPushButton, no need for a subclass!) to a slot in your controller class (seems like you're using MainWindow for that), like this:
connect(button, &QPushButton::clicked, this, &MainWindow::onButtonClicked
- in your slot, get the necessary data:
MainWindow::onButtonClicked() { actual_ennemy->getItems().getItem(i); }
- of course, you also need to know which
i
to use, andactual_ennemy
needs to be set. I know too little of your program to tell you how to do that
- signal cannot have implementation (you can't have
-
@Lc44bzh said in Connect signals with arguments:
emitclicked(actual_ennemy->getItems().getItem(i))
You can't pass parameters to signal when you connect. Parameters are passed to the signal when the signal is emitted. Same applies to slots: those get their parameters from the signal.
Please read https://doc.qt.io/qt-5/signalsandslots.html There are also examples.wrote on 4 May 2021, 11:03 last edited by@jsulm said in Connect signals with arguments:
@Lc44bzh said in Connect signals with arguments:
emitclicked(actual_ennemy->getItems().getItem(i))
You can't pass parameters to signal when you connect. Parameters are passed to the signal when the signal is emitted. Same applies to slots: those get their parameters from the signal.
Please read https://doc.qt.io/qt-5/signalsandslots.html There are also examples.I saw on https://openclassrooms.com/fr/courses/1894236-programmez-avec-le-langage-c/1899731-utilisez-les-signaux-et-les-slots that it may be possible. Never mind.
@sierdzio said in Connect signals with arguments:
There are several issues with your code:
- signal cannot have implementation (you can't have
emitclicked()
body in cpp file, only declaration in header) connect
statement only connects signals and slot, you cannot provide any actual data there likeactual_ennemy->getItems().getItem(i))
. The only stuff you should provide there are argument types. Even better: use new functor-based connection syntax https://doc.qt.io/qt-5/signalsandslots-syntaxes.html- connect is called only once, when a connection is made - so it has no idea what data will be sent through it later
So QT think i call a signal from QPushButton
Not quite, your code is simply wrong. Here is how to fix it:
- connect your button's
clicked()
signal (it can be a normal QPushButton, no need for a subclass!) to a slot in your controller class (seems like you're using MainWindow for that), like this:
connect(button, &QPushButton::clicked, this, &MainWindow::onButtonClicked
- in your slot, get the necessary data:
MainWindow::onButtonClicked() { actual_ennemy->getItems().getItem(i); }
- of course, you also need to know which
i
to use, andactual_ennemy
needs to be set. I know too little of your program to tell you how to do that
Thank you, I used your solution and it's working. I defined the objectname of each button with i, and when I am in onButtonClicked, I just read the sender object name to get the index of my item.
Thank for your help both of you.
- signal cannot have implementation (you can't have
-
@jsulm said in Connect signals with arguments:
@Lc44bzh said in Connect signals with arguments:
emitclicked(actual_ennemy->getItems().getItem(i))
You can't pass parameters to signal when you connect. Parameters are passed to the signal when the signal is emitted. Same applies to slots: those get their parameters from the signal.
Please read https://doc.qt.io/qt-5/signalsandslots.html There are also examples.I saw on https://openclassrooms.com/fr/courses/1894236-programmez-avec-le-langage-c/1899731-utilisez-les-signaux-et-les-slots that it may be possible. Never mind.
@sierdzio said in Connect signals with arguments:
There are several issues with your code:
- signal cannot have implementation (you can't have
emitclicked()
body in cpp file, only declaration in header) connect
statement only connects signals and slot, you cannot provide any actual data there likeactual_ennemy->getItems().getItem(i))
. The only stuff you should provide there are argument types. Even better: use new functor-based connection syntax https://doc.qt.io/qt-5/signalsandslots-syntaxes.html- connect is called only once, when a connection is made - so it has no idea what data will be sent through it later
So QT think i call a signal from QPushButton
Not quite, your code is simply wrong. Here is how to fix it:
- connect your button's
clicked()
signal (it can be a normal QPushButton, no need for a subclass!) to a slot in your controller class (seems like you're using MainWindow for that), like this:
connect(button, &QPushButton::clicked, this, &MainWindow::onButtonClicked
- in your slot, get the necessary data:
MainWindow::onButtonClicked() { actual_ennemy->getItems().getItem(i); }
- of course, you also need to know which
i
to use, andactual_ennemy
needs to be set. I know too little of your program to tell you how to do that
Thank you, I used your solution and it's working. I defined the objectname of each button with i, and when I am in onButtonClicked, I just read the sender object name to get the index of my item.
Thank for your help both of you.
wrote on 4 May 2021, 11:09 last edited by Pl45m4 5 Apr 2021, 11:14@Lc44bzh said in Connect signals with arguments:
I saw on https://openclassrooms.com/fr/courses/1894236-programmez-avec-le-langage-c/1899731-utilisez-les-signaux-et-les-slots that it may be possible. Never mind.
The tutorial itself is not wrong. Maybe you misunderstood it :)
I defined the objectname of each button with i, and when I am in onButtonClicked, I just read the sender object name to get the index of my item
Using
objectNames
is possible, but not the best solution, since you heavily rely on them then.
(Edit: actually, using objectNames to get your indices is bad style and very ugly)Edit:
Depends on your use case and how the rest of your game should work, but consider using something like a
QMap
or any other container to store your items and/or map them to your buttons / enemies, or whatever you want to do with them. - signal cannot have implementation (you can't have
-
@jsulm said in Connect signals with arguments:
@Lc44bzh said in Connect signals with arguments:
emitclicked(actual_ennemy->getItems().getItem(i))
You can't pass parameters to signal when you connect. Parameters are passed to the signal when the signal is emitted. Same applies to slots: those get their parameters from the signal.
Please read https://doc.qt.io/qt-5/signalsandslots.html There are also examples.I saw on https://openclassrooms.com/fr/courses/1894236-programmez-avec-le-langage-c/1899731-utilisez-les-signaux-et-les-slots that it may be possible. Never mind.
@sierdzio said in Connect signals with arguments:
There are several issues with your code:
- signal cannot have implementation (you can't have
emitclicked()
body in cpp file, only declaration in header) connect
statement only connects signals and slot, you cannot provide any actual data there likeactual_ennemy->getItems().getItem(i))
. The only stuff you should provide there are argument types. Even better: use new functor-based connection syntax https://doc.qt.io/qt-5/signalsandslots-syntaxes.html- connect is called only once, when a connection is made - so it has no idea what data will be sent through it later
So QT think i call a signal from QPushButton
Not quite, your code is simply wrong. Here is how to fix it:
- connect your button's
clicked()
signal (it can be a normal QPushButton, no need for a subclass!) to a slot in your controller class (seems like you're using MainWindow for that), like this:
connect(button, &QPushButton::clicked, this, &MainWindow::onButtonClicked
- in your slot, get the necessary data:
MainWindow::onButtonClicked() { actual_ennemy->getItems().getItem(i); }
- of course, you also need to know which
i
to use, andactual_ennemy
needs to be set. I know too little of your program to tell you how to do that
Thank you, I used your solution and it's working. I defined the objectname of each button with i, and when I am in onButtonClicked, I just read the sender object name to get the index of my item.
Thank for your help both of you.
@Lc44bzh hi and welcome to devnet,
You misunderstood the tutorial. You are mixing the function signature with function parameters.
The connect statement in its old form takes string parameters that are the signature of the signal function and the signature of the slot function. You can't pass parameter values in there (nor can you with the syntax).
- signal cannot have implementation (you can't have
-
@jsulm said in Connect signals with arguments:
@Lc44bzh said in Connect signals with arguments:
emitclicked(actual_ennemy->getItems().getItem(i))
You can't pass parameters to signal when you connect. Parameters are passed to the signal when the signal is emitted. Same applies to slots: those get their parameters from the signal.
Please read https://doc.qt.io/qt-5/signalsandslots.html There are also examples.I saw on https://openclassrooms.com/fr/courses/1894236-programmez-avec-le-langage-c/1899731-utilisez-les-signaux-et-les-slots that it may be possible. Never mind.
@sierdzio said in Connect signals with arguments:
There are several issues with your code:
- signal cannot have implementation (you can't have
emitclicked()
body in cpp file, only declaration in header) connect
statement only connects signals and slot, you cannot provide any actual data there likeactual_ennemy->getItems().getItem(i))
. The only stuff you should provide there are argument types. Even better: use new functor-based connection syntax https://doc.qt.io/qt-5/signalsandslots-syntaxes.html- connect is called only once, when a connection is made - so it has no idea what data will be sent through it later
So QT think i call a signal from QPushButton
Not quite, your code is simply wrong. Here is how to fix it:
- connect your button's
clicked()
signal (it can be a normal QPushButton, no need for a subclass!) to a slot in your controller class (seems like you're using MainWindow for that), like this:
connect(button, &QPushButton::clicked, this, &MainWindow::onButtonClicked
- in your slot, get the necessary data:
MainWindow::onButtonClicked() { actual_ennemy->getItems().getItem(i); }
- of course, you also need to know which
i
to use, andactual_ennemy
needs to be set. I know too little of your program to tell you how to do that
Thank you, I used your solution and it's working. I defined the objectname of each button with i, and when I am in onButtonClicked, I just read the sender object name to get the index of my item.
Thank for your help both of you.
wrote on 5 May 2021, 07:06 last edited by@Lc44bzh said in Connect signals with arguments:
I saw on https://openclassrooms.com/fr/courses/1894236-programmez-avec-le-langage-c/1899731-utilisez-les-signaux-et-les-slots that it may be possible. Never mind.
In the connect statement you only have the types of the parameters. However, you cannot provide the actual parameters in the connect statement. Instead you have to provide them when you call (emit) the signal. A button has no parameters when clicked. You can connect
clicked()
to some slot which extracts the information and then emit another signal with this parameter connected to the slot you already initially had.There might be a shortcut for what you want to do. All this assumes that you already know
actual_ennemy
and the indexi
when you create the button (which I assume is the case). Then you can replace your connect with the following:connect(button, &QPushButton::clicked, this, [this](){ new_item(actual_ennemy->getItems().getItem(i)); });
This is the newer connect syntax. Your
button
can now be aQPushButton
again. The third parameter toconnect
is just a context object.this
makes sense in this context. Instead of an actual slot here we connect to a lambda function. Depending on which variables are member of your class and which are local variables you might have to capture additional variables in the lambda. This is the easiest way I know to quickly connect a signal with fewer arguments than the required slot. - signal cannot have implementation (you can't have
-
wrote on 5 May 2021, 07:33 last edited by
Thanks for your answers. Now, when I create a button, I store the item pointer associated with him. And I use connect with Item type, so I can get the item related to my button. Here is my code, and it work properly :
itembutton.h :#ifndef ITEMBUTTON_H #define ITEMBUTTON_H #include <QPushButton> #include "item.h" #include <iostream> using namespace std; class ItemButton : public QPushButton { Q_OBJECT public: ItemButton(Item * it, QWidget * parent); Q_SIGNAL void clicked(Item *); private: Q_SLOT void reemitClicked(); private: Item *myitem; }; #endif // ITEMBUTTON_H
itembutton.cpp :
#include "itembutton.h" ItemButton::ItemButton(Item *it, QWidget *parent) : QPushButton(parent) { myitem = it; connect(this, SIGNAL(clicked()), this, SLOT(reemitClicked())); } void ItemButton::reemitClicked() { emit clicked(myitem); }
connect function in mainwindow.cpp :
connect(button, SIGNAL(clicked(Item*)), this, SLOT(new_item(Item*)));
-
Thanks for your answers. Now, when I create a button, I store the item pointer associated with him. And I use connect with Item type, so I can get the item related to my button. Here is my code, and it work properly :
itembutton.h :#ifndef ITEMBUTTON_H #define ITEMBUTTON_H #include <QPushButton> #include "item.h" #include <iostream> using namespace std; class ItemButton : public QPushButton { Q_OBJECT public: ItemButton(Item * it, QWidget * parent); Q_SIGNAL void clicked(Item *); private: Q_SLOT void reemitClicked(); private: Item *myitem; }; #endif // ITEMBUTTON_H
itembutton.cpp :
#include "itembutton.h" ItemButton::ItemButton(Item *it, QWidget *parent) : QPushButton(parent) { myitem = it; connect(this, SIGNAL(clicked()), this, SLOT(reemitClicked())); } void ItemButton::reemitClicked() { emit clicked(myitem); }
connect function in mainwindow.cpp :
connect(button, SIGNAL(clicked(Item*)), this, SLOT(new_item(Item*)));
wrote on 5 May 2021, 07:37 last edited by@Lc44bzh said in Connect signals with arguments:
Now, when I create a button, I store the item pointer associated with him. And I use connect with Item type, so I can get the item related to my button.
Well done. This is also a proper solution. It seems that you significantly improved your understanding of Qt's signals and slots.
-
Thanks for your answers. Now, when I create a button, I store the item pointer associated with him. And I use connect with Item type, so I can get the item related to my button. Here is my code, and it work properly :
itembutton.h :#ifndef ITEMBUTTON_H #define ITEMBUTTON_H #include <QPushButton> #include "item.h" #include <iostream> using namespace std; class ItemButton : public QPushButton { Q_OBJECT public: ItemButton(Item * it, QWidget * parent); Q_SIGNAL void clicked(Item *); private: Q_SLOT void reemitClicked(); private: Item *myitem; }; #endif // ITEMBUTTON_H
itembutton.cpp :
#include "itembutton.h" ItemButton::ItemButton(Item *it, QWidget *parent) : QPushButton(parent) { myitem = it; connect(this, SIGNAL(clicked()), this, SLOT(reemitClicked())); } void ItemButton::reemitClicked() { emit clicked(myitem); }
connect function in mainwindow.cpp :
connect(button, SIGNAL(clicked(Item*)), this, SLOT(new_item(Item*)));
wrote on 5 May 2021, 08:10 last edited by@Lc44bzh
Indeed well done!As it's my bug-bear, can I suggest you go further and change over from using
SIGNAL
/SLOT()
macros to the New Signal Slot Syntax? You really will benefit, with compile-time checking of your signals, slots & parameters. Note how @SimonSchroeder used this in his example (it used a lambda for the slot, which is more complicated but very powerful, but nonetheless used the new style syntax, as one has to anyway for lambdas).For example,
connect(this, SIGNAL(clicked()), this, SLOT(reemitClicked()));
would be better written as
connect(this, &ItemButton::clicked, this, &ItemButton::reemitClicked);
1/10