QT4 no such slot error - c++

I know there are many many questions that are just the same, but none of them helps me:
class Form1 : public QMainWindow {
Q_OBJECT
public:
Form1();
virtual ~Form1();
public slots:
void langChange(const char* lang_label);
private:
Ui::Form1 widget;
void setLangStrings();
};
From1 constructor:
Form1::Form1() {
widget.setupUi(this);
connect(widget.btnL0, SIGNAL(clicked(bool)), this, SLOT(langChange("en")));
connect(widget.btnL1, SIGNAL(clicked(bool)), this, SLOT(langChange("fr")));
setLangStrings();
}
And I also have this langChange function implemented:
void Form1::langChange(const char* lang_label)
{
GL_LANG = lang_label;
setLangStrings();
}
I get this stupid error when the connect function is called:
No such slot Form1::langChange("sl") in Form1.cpp:15
I'm using NetBeans with QDesigner for the UI. I must say this QT4 is very difficult to learn.

You simply can't connect SIGNAL with bool as argument to SLOT with const char* as argument. To do this kind of stuff you have to use QSignalMapper. You have an example how to use it inside documentation. In your case, it's very simple, so you should handle it easly.

The SLOT function must have the same signature than the SIGNAL function
Edit: From the official Qt documentation (http://qt-project.org/doc/qt-4.8/signalsandslots.html):
The signature of a signal must match the signature of the receiving
slot. (In fact a slot may have a shorter signature than the signal it
receives because it can ignore extra arguments.)

Related

How to pass a signal as function parameter?

So i am looking to make our own generic inherited checkbox class that will be able to take in some values in its constructor and pop out a widget that is fully connected to our model in the manner we need.
Currently we do something like this within our view
connect(checkboxWidget, &QCheckbox::Clicked, this, &VMyView::Signal);
Which emits the Signal from VMyView when the checkbox is clicked.
If i wanted to pass that signal as a parameter into my new inherited class to be hooked up in its own connect statement, how would I do so?
Research has shown me i can pass a const char* but i get compilation errors that the signal/slot do not match.
Example
CheckBox(View myView, const char* signal)
{
connect(this, &QCheckBox::Clicked, myView, signal);
}
Returns an error that Signal and slot arguments are not compatible. Ive also tried SIGNAL(signal) with the same result.
The solution ended up being fairly simple in the end
Instead of using this from within my View
connect(pCheckbox, &QCheckBox::clicked, this, &MyView::Signal);
I use
connect(this, &QCheckBox::clicked, View, signal);
Where signal and comes into my function via a function pointer
MyCheckBox::MyCheckBox(QWidget* parent, MyView* View, void(MyView::*signal)(bool))
The key takeaway is
void(MyView::*signal)(bool)
is equal too
&MyView::Signal
I think the major issue here is that signals are not static member functions. Thus they require a pointer to an instance of the class to be called correctly. So you cannot just pass in things like &VMyView::Signal, as there's no corresponding this pointer attached to the function. (This is why most of the QObject::connect() overloads require an instance to the sender/receiver objects.)
One way to solve this is to create a function object, which contains both the member function pointer and the pointer to the object on which to call it. This can be passed to the QObject::connect() function just fine.
Here's an example:
// objects.h
#include <QtCore>
class Receiver : public QObject
{
Q_OBJECT
public:
Receiver( QObject *parent = nullptr)
: QObject(parent)
{
}
~Receiver() { }
signals:
void sig(void);
};
class Sender : public QObject
{
Q_OBJECT
public:
Sender(std::function<void(void)> &bound_signal, QObject *parent = nullptr)
: QObject(parent)
{
// automatically emit `Sender::sig` on a timer, for testing.
timer = new QTimer(this);
timer->setInterval(1000);
QObject::connect(timer, &QTimer::timeout, this, &Sender::sig);
QObject::connect(this, &Sender::sig, bound_signal);
timer->start();
}
~Sender() { }
signals:
void sig(void);
private:
QTimer *timer;
};
And then a main function:
// main.cc
#include <QtCore>
#include "objects.h"
int main(int argc, char *argv[])
{
QCoreApplication app(argc, argv);
Receiver receiver; // object to receive the signal
// Bind the receiver's signal to the instance of the class
std::function<void(void)> signal = std::bind(&Receiver::sig, &receiver);
// Create a Sender, which will connect its own signal to the
// given bound signal
Sender sender(signal);
QObject::connect(&receiver, &Receiver::sig,
[]() -> void { qDebug() << "received"; });
return app.exec();
}
So, in your case, the Receiver and its signal would be replaced by VMyView and the signals you want to chain, and Sender would be the custom checkbox class you've implemented. Then in the constructor of the checkbox class, connect whatever signals you want to the given bound signals. You can also pass in a list of bound signals, e.g., std::list<std::function<void(void)>> &bound_signals.
I have to say, though, I'm not sure what this buys you. You'll need to write the connection logic somewhere, and I don't see why it needs to be in the constructor of the checkbox class. Wherever the checkbox and the VMyView class are created and used, that seems like a better place to put the connection code. It's more obvious, less convoluted, and there's better separation of concerns. The checkbox class shouldn't have to know or care what signals/slots its connected to. The application logic (i.e., where the objects are used) should define how the objects interact with one another.

QObject::connect: No such slot (Qt, C++)

I can run the program but the button cannot access the send function. I get this hint:
QObject::connect: No such slot Mail::send(emailInput, pwdInput)
Someone knows what's my mistake?
mail.h:
#ifndef MAIL_H
#define MAIL_H
#include <QWidget>
namespace Ui {
class Mail;
}
class Mail : public QWidget
{
Q_OBJECT
public:
explicit Mail(QWidget *parent = 0);
~Mail();
public slots:
void send(std::string email, std::string pwd);
private:
Ui::Mail *ui;
};
#endif // MAIL_H
mail.cpp:
Mail::Mail(QWidget *parent) :
QWidget(parent)
{
QLineEdit *edt1 = new QLineEdit(this);
grid->addWidget(edt1, 0, 1, 1, 1);
std::string emailInput = edt1->text().toStdString();
...
QObject::connect(acc, SIGNAL(clicked()),this, SLOT(send(emailInput, pwdInput)));
}
void Mail::send(std::string email, std::string pwd){
...
}
In fact, you have 2 mistakes in your code:
the SLOT macro takes the type of arguments as parameter not their name, then the code should be : SLOT(send(std::string, std::string)).
You try to connect a SIGNAL which has less argument than the SLOT which is impossible.
In order to avoid all these problems you can use the new signal/slot syntax (if your are using Qt5):
QObject::connect(acc, &QLineEdit::clicked, this, &Mail::onClicked);
I also invite you to use the QString class instead of std::string when working with Qt, it is a lot easier.
That depends on what you want to do:
If emailInput and pwdInput come from widgets, you have to write an intermediate slot that will get the values and call send.
If they are local variables, the easiest is probably to use a lambda.
Should be
QObject::connect(acc, SIGNAL(clicked()),this, SLOT(send(std::string, std::string)));
Macros SIGNAL and SLOT expect method's signature as argument(s).
Additionally, you can connect a signal to a slot of less arity, not the vice versa; here, QObject would not simply know what should be substituted for slot's arguments. You can use the overload of connect that accepts an arbitrary Functor (an anonymous closure, most likely) as slot:
QObject::connect(acc, SIGNAL(clicked()), [=](){ send(std::string(), std::string()); });
Thirdly, were you to use QString instead of std::string, you would not have that heavy copy overhead when passing by value.

How to build a generic method to connect the notifySignal of different Q_PROPERTY types to a void slot(QVariant) from the property char * name?

I'm trying to write a method, with two parameters : the Q_PROPERTY name (char *) and the QObject * associated with, that permit to connect the notifySignal (if exists) of the Q_PROPERTY, to a void slot(QVariant), or to a slot dynamically builded which will call a void method(QVariant). The signature of the signal can vary according to the type of the parameter.
How can I achieve that in Qt 5? Maybe it's impossible, but I will not stop searching while I'm not sure of that.
So I think I have 3 solutions:
building dynamically a slot of the exact signature of the signal, from the signal name, and call a method(QVariant) in it, using the old Qt connect way:
connect(sender, SIGNAL (valueChanged(QString,QString)),
receiver, SLOT (updateValue(QString)) );
using the new Qt 5 connect system:
connect(sender, &Sender::valueChanged,receiver, &Receiver::updateValue );
building all slots signatures that can be used with QVariant.
Althougt, I don't know how to build a slot dynamically that call a specified method for the first solution ; I don't know how to retrieve the function pointer from the QMetaMethod of the notifySignal, for the second solution ; maybe the last solution is the best way, and easy to achieve, but it seams a bit extreme.
What do you think about it?
For "building a slot dynamically" there are private APIs in Qt (look for QMetaObjectBuilder or similar classes). However that doesn't solve the problem of the connection.
Note that QObject::connect is overloaded to take QMetaMethods as signals and slots. So you can easily build a "receiver" class object (for the only purpose of remembering which property it's acting upon):
class Receiver : public QObject {
Q_OBJECT
public:
explicit Receiver(const char *property, QObject *parent = 0)
: QObject(parent),
m_property(property)
{}
signals:
void propertyChangedForObject(const char *property, QObject *object);
public slots:
void onPropertyChanged() {
emit propertyChangedForObject(m_property, sender());
}
private:
const char * const m_property;
};
And hook it up in your method.

c++ QPushButton signal and slot

I have a problem creating a QPushButton and linking its signal to my slots. First, I created a class with the slot:
class A : public QWidget{
public slots:
void handleButton();
};
There is my handleButton function in the .cpp
void A::handleButton(int row, int col){
m_button->setText("Example");
// resize button
m_button->resize(100,100);
}
Then I want to connect the button.
QObject::connect(m_button, SIGNAL(clicked()), qApp, SLOT(handleButton()));
But I got an error when I start the application:
"No such slot"
Make sure that qApp is an object of class A (i.e. where your slot is defined).
That said, the signatures are wrong: a signal links to a slot only if the signature match
http://qt-project.org/doc/qt-4.8/signalsandslots.html
The signals and slots mechanism is type safe: The signature of a signal must match the signature of the receiving slot.
And your slot hasn't the right signature:
http://qt-project.org/doc/qt-4.8/qabstractbutton.html#clicked
void QAbstractButton::clicked ( bool checked = false ) [signal]
You have a few errors in this code, if you define "void handlebutton()" then you must implement void handlebutton() NOT void handlebutton(inx x, int y) this code should not even compile.
More: in QT you CAN ONLY connect SIGNALS and SLOTS with the same parameters so you can connect SIGNAL(clicked()) with SLOT(handlebutton()) but not SIGNAL(clicked() with SLOT(handleButton(int, int)).
Another problem is that connect is executed at runtime so You must compile and run before Qt can show you the error.
So a possible solution is:
define and implement the slot void handlebutton() and connect that to the signal clicked(), then define another method handleButton (int x, int y) that you will call from inside handleButton().
I really hope that makes sense to you.
Your class definition should look like :
class A : public QWidget
{
Q_OBJECT
public slots:
void handleButton(int, int);
};
And you should connect it like:
QObject::connect(m_button, SIGNAL(clicked()),qApp, SLOT(handleButton(int a, int b)));
where a and b are variables for row and column.
This should work. Try understanding basic C++. :)

Qt4: connect slot and signal from other forms

I have a small problem. I want run function in MainWindow from AnotherWindow. I can't set connect() for it.
Main class: MainWindow
Other form: AnotherWindow
Function in main class: setVariable(QString)
Function in other form: btnClicked()
I have now connected button signal clicked():
// In AnotherWindow.cpp
connect(ui->btnOK, SIGNAL(clicked()), this, SLOT(btnOkClicked()));
// Function in same file
void interfaceWindow::btnOkClicked() {
/* Some actions - emit signal? */
this->close();
}
btnOkClicked() are declared as private slot.
// In MainWindow.cpp
void MainWindow::setVariable(QString _var) {
this->var = _var;
}
setVariable(QString) are declared as public slot.
How I can send variable from AnotherForm (from btnOkClicked() function) to MainWindow (setVariable(QString) function) ? How and where I must send signal and make connection?
I readed about signals and slots, but my code don't work - I don't paste it here because it's terrible :)
Any help for Qt newbie?
You need to have an reference of AnotherWindow in MainWindow OR vice versa. Then you need the following things:
// AnotherWindow.h
signals:
void buttonOkClickedSignal(QString var);
// AnotherWindow.cpp
void interfaceWindow::btnOkClicked() {
emit buttonOkClickedSignal("The button got clicked!");
this->close();
}
Next step varies based on whether MainWindow has reference to AnotherWindow or vice versa. You can either:
// AnotherWindow.cpp
connect(this, SIGNAL(buttonOkClickedSignal(QString), &mainWindow, SLOT(setVariable(QString)));
or:
// MainWindow.cpp
connect(&anotherWindow, SIGNAL(buttonOkClickedSignal(QString), this, (SLOT(setVariable(QString)));
If you are invoking the slot through signal it shouldn't matter whether it's private or public (see Qt Documentation).
Hope this helps.
I'm not entirely sure I understand your question, but let me try.
You want to be able to fire a slot in another class. There are a few ways you can do that.
Declare one as a friend class to the other. Then they can see the protected and private variables/memebers
It is possible to make slots static so you can call them without a class object.
For example,
class MainWindow {
private slot:
void setVariable(QString);
}
class AnotherWindow {
friend class MainWindow;
MainWindow *window;
public:
AnotherWindow() {
connect(this, SIGNAL(fire(QString)), window, SLOT(setVariable(QString)));
}
signals:
void fire(QString);
public slots:
void onButtonClicked() {
emit fire(QString);
}
}
The previous is pseudocode so don't expect it to compile. I think this is what you want. Basically since your slot is private on MainWindow you need to make it a friend. To connect, it needs to be a member. Then when the onButtonClicked slot is evoked, then it fire()s the setVarialbe() slot.
Here is a simple code for your another window:
class MyWidget : public QWidget
{
Q_OBJECT
public:
MyWidget(QWidget * parent = 0)
{
okBtn = new QPushButton ("I am Ok!");
MyData = "";
connect(okBtn ,SIGNAL(clicked()),this,SLOT(OnOk()));
}
~MyWidget();
private:
QString MyData;
QPushButton * okBtn;
//something that modify string MyData
signals:
void MyDataSignal(QString);
//Internal slot that emits signal with proper data
private slots:
void OnOk()
{
if(MyData!="")
{
emit MyDataSignal(MyData);
}
}
};
Now in MainWindow create an object of MyWidget (suppose myWid)and connect it to slot
connect(myWid, SIGNAL(MyDataSignal(QString)),this,SLOT(OnMyWidOkClicked(QString)));
the signal will pass string to slot.
While making signals and slots keep in mind following points:
To connect a signal to a slot (or to another signal), they must have the same parameter
Parameters should be in the same order in both signal and slot.
if a signal has more parameters than the slot it is connected to, the additional parameters are simply ignored but opposite is not possible.
If you will connect a signal that have unmatched parameters to slot then no compile time error will occur but at run time command window will show a warning that signal/slot/connection does not exist.