Qt connect doesn't recognize with lambda expression - c++

I'm designed a QTableWidget with QPushButton, I would like to connect these buttons with a slot to hide some rows.
I'm using a lambda expression to pass a number of a row. But the compiler doesn't recognized this expression :
connect(this->ui->tableWidget->cellWidget(i,0),&QPushButton::clicked,[this,i]{hideRows(i);});
I have this error:
error: no matching function for call to 'SoftwareUdpater::MainWidget::connect(QWidget*, void (QAbstractButton::*)(bool), SoftwareUdpater::MainWidget::displayTable()::<lambda(int)>)'
The function hideRows(int) is declared as a function. And, as a slot, it doesn't work,
CONFIG += c++11 is added in pro file,
My class MainWidget inherits from QWidget,
Q_OBJECT is added in the header.
So I don't udnerstand why connect() is not recognized by Qt 5.9.1 MinGw 32bit.
Edit: [this,i]() instead of [this](const int i) for the lambda expression

Your connection is wrong. You can't connect a function that doesn't take parameters (clicked()) with a function that takes parameters (your lambda). To verify that this is the case, just do this:
connect(this->ui->tableWidget->cellWidget(i,0),&QPushButton::clicked,[this](){});
And see that it will compile. You have to make your design in such a way that signals and slots are compatible.
Also avoid using lambdas in signals and slots. Read the caveats here.

I was reading your comments on the accepted answer and noticed the root of the problem: This error is being thrown because the effective type of the object — as supplied to QObject::connect; i.e QWidget in your case — does not define the referenced signal QPushButton::clicked.
What likely happened is that the QPushButton pointer was cast into a QWidget and then that pointer was given to connect instead of the original which defines the signal.
Cast the pointer back to a QPushButton * and the error should go away.

Related

Qt signal on buttongroup not connected

I have a buttongroup defined with two radiobuttons
buttonGroupFFTDimension = new QButtonGroup(this);
buttonGroupFFTDimension->addButton(ui->radioButton1D, 1);
buttonGroupFFTDimension->addButton(ui->radioButton2D, 2);
buttonGroupFFTDimension->setExclusive(true);
ui->radioButton1D->setChecked(true);
The connect also compiles
connect(this->buttonGroupFFTDimension, static_cast<void(QButtonGroup::*)(int)>(&QButtonGroup::buttonClicked),
this, &MainWindow::on_buttonGroupFFTDimension_buttonClicked);
but it throws and error at runtime
QMetaObject::connectSlotsByName: No matching signal for on_buttonGroupFFTDimension_buttonClicked(int)
I admit that I am not familiar with the new connect syntax, but also do not see the obvious error. What is wrong?
The message shown is because you are using Qt Designer and it uses the connectSlotsByName method to connect various elements, it recognizes the format on_somesender_somesignal, and in your case matches your slot.
First solution: It iss unnecessary to use the connect function, this will automatically do it. Also I think that the slot does not have as parameter the type int that requires.
In your case the slot should be as follows:
private slots:
void on_buttonGroupFFTDimension_buttonClicked (int val);
Another possible solution is to rename the slot, after that you run make clean and qmake.

connecting a basic signal mousepress

I am using QCustomPlot where I am trying to write a code that will rescale my axes once the user press the mouse and drags. I did:
connect(ui->plot, SIGNAL(mousePress(QMouseEvent *event)), this, SLOT(mousedrag(QMouseEvent*)));
and I keep getting:
QObject::connect: No such signal QCustomPlot::mousePress(QMouseEvent
*event)
But mouseWheel(QWheelEvent*) and both mouseWheel and mousePress have signals declared in the QCustomPlot library.
Where am I going wrong? Also if someone has a better signal to trigger my function mousedrag(QMouseEvent*) which rescales the the y2 axis according to y1 axis I am open for suggestions.
The signal signature passed to connect is invalid. The parameter names are not a part of the signature. You should also remove any whitespace so that connect doesn't have to normalize the signatures. A normalized signature has no unnecessary whitespace and outermost const and reference must be removed, e.g. SIGNAL(textChanged(QString)), not SIGNAL(textChanged(const QString &)).
remove
vvvvv
connect(ui->plot, SIGNAL(mousePress(QMouseEvent *event)), this,
SLOT(mousedrag(QMouseEvent*)));
Do the below instead:
// Qt 5
connect(ui->plot, &QCustomPlot::mousePress, this, &MyClass::mousedrag);
// Qt 4
connect(ui->plot, SIGNAL(mousePress(QMouseEvent*)), SLOT(mousedrag(QMouseEvent*));
Sidebar
TL;DR: This sort of API design is essentially a bug.
Events and signal/slot mechanism are different paradigms that the QCustomPlot's design mangles together. The slots connected to these signals can be used in very specific and limited ways only. You have to use them exactly as if they were overloads in a derived class. This means:
Each signal must have either 0 or 1 slots connected to it.
The connections must be direct or automatic to an object in the same thread.
You cannot use queued connections: by the time the control returns to the event loop, the event has been destroyed and the slot/functor will be using a dangling pointer.
When using the "old" signals/slot connection syntax, i.e. the one using the SIGNAL and SLOT macros in the connect() statement, you shall not provide the names of the parameters, only their types.
In other words:
SIGNAL(mousePress(QMouseEvent *event)) // WRONG, parameter name in there!
SIGNAL(mousePress(QMouseEvent *)) // GOOD
SIGNAL(mousePress(QMouseEvent*)) // BETTER: already normalized
So simply change your statement to
connect( ui->plot, SIGNAL(mousePress(QMouseEvent*)),
this, SLOT(mousedrag(QMouseEvent*)) );

Qt SLOT macro used as function argument

I'm going through the calculator example that was installed with Qt 5.1.1 and there is a private function used to create button widgets (Button inherits QToolButton):
Button *Calculator::createButton(const QString &text, const char *member)
{
Button *button = new Button(text);
connect(button, SIGNAL(clicked()), this, member);
return button;
}
The example calls the above function to create several different buttons e.g.:
createButton(tr("Clear"), SLOT(clear()));
Where void clear() was declared as a private slot. I understand what the code is trying to do but I want to know why does passing SLOT(clear()) as the const char *member work. I can't seem to find much online that would explain using SLOT like that.
As you can see in the documentation of the connect method, the function signature expects the const char* type. These are the corresponding defines from QtCore:
Q_CORE_EXPORT const char *qFlagLocation(const char *method);
...
# define SLOT(a) qFlagLocation("1"#a QLOCATION)
# define SIGNAL(a) qFlagLocation("2"#a QLOCATION)
It is a bit more complex and you can see the details in here, but I simplified it for the sake of the explanation and understanding.
This "old" signal-slot syntax is basically "string" based, and that is also the fundamental flaw with it. This was fixed in Qt 5, however. It is now closer what you seem to imply with your question so that you would rather expect it to be function or method pointers since you eventually pass such an element to the SLOT and SIGNAL moc tokens.
For completeness, the corresponding SIGNAL and SLOT tokens (i.e. Q_SLOTS, Q_SIGNALS, etc) are processed by the meta object compiler, aka. moc, the way that it puts those into the ".moc" files. You can see it yourself if you open those files up. For further details, look into the moc source code which can be found in here.

signal slot issue in qt 5

I have one c++ class and have one signal in it and want to connect that signal with slot another C++ class. Here is my code
class Data : public QObject
{
Q_OBJECT
public:
static Data *instance(void);
signals:
void sendUserID(const QString& userId);
private:
static Data *s_instance;
};
here is my Slot in another class
void DataDetails::seTUserID(const QString user_id)
{
QAndroidJniObject user_id = QAndroidJniObject::fromString(user_id);
QAndroidJniObject::callStaticMethod<void>("com/user/data/userActivity",
"setUserID",
"(Ljava/lang/String;)V",
user_id.object<jstring>());
}
The idea is to access the value of user_id from Data class to DataDetails class
The connection is trying is
QObject::connect(&s_instance, SIGNAL(sendUserID(uid), this, SIGNAL(setUserID(uid))
any other id to get uid to other class is also fine ..
Generally speaking, when you encounter an issue with QObject::connect...
Make sure you have your declarations in order:
Both classes need the Q_OBJECT macro in their declaration.
Make sure your slot is actually declared as a slot (i.e. is part of a public slot: section).
Because connecting signals and slots just uses character strings evaluated at run-time, it's possible to write absolute nonsense and have it compile. In my experience, errors caused by typos are pretty common.
Always test in an environment where you can see your application's console output. Failed connect calls will usually trigger an error message printed to stderr.
Double-check your method names and signatures. Code will still compile even if you've made a typo!
For debugging, use assertions (e.g. bool c = connect(...); Q_ASSERT(c);) to catch missed connections early.
Alternatively, you can use the QMetaMethod-based version of QObject::connect, introduced in Qt 4.8, to avoid some of these issues.
In your particular case:
You've got a typo in the function declaration: it's called seTUserID but you're using setUserID in the connect call.
You're using variable names, not function signatures, in your signal and slot names. Qt expects to see QObject::connect(&s_instance, SIGNAL(sendUserID(const QString), this, SLOT(setUserID(const QString))
You've got a signal connected to another signal, which is valid but doesn't do what you want (it's usually used to chain stuff like this: SomeChildWidget's signal -> MyClass1's signal -> MyClass2's slot).
Check that seTUserID definition is marked as slot. You are probably calling connect in some Data method (because you are using private member directly). Are you trying to use a ref to a pointer to s_instance O_o? Write sendUserID(const Qstring) (the signature of a signal) rather then sendUserID(uid). The same situation with setUserID. You are trying to connect to this pointer and want to send info to another class!? Use new style of Qt connecting signals and slots (pointers to members), with was introduced in Qt 5. Check for setUserID has written right.

Qt: having problems responding on QWebView::linkClicked(QUrl) - slot signal issue

I am pretty new with Qt.
I want to respond to linkClicked in QWebView.
I tried connect like this:
QObject::connect(ui->webView, SIGNAL(linkClicked(QUrl)),
MainWindow,SLOT(linkClicked(QUrl)));
But I was getting error: C:/Documents and Settings/irfan/My Documents/browser1/mainwindow.cpp:9: error: expected primary-expression before ',' token
When I do this using UI Editing Signals Slots:
I have in header file declaration of slot:
void linkClicked(QUrl &url);
in source cpp file :
void MainWindow::linkClicked(QUrl &url)
{
QMessageBox b;
b.setText(url->toString());
b.exec();
}
When I run this it compiles and runs but got a warning :
Object::connect: No such slot MainWindow::linkClicked(QUrl)
in ui_mainwindow.h:100
What is proper way of doing this event handling?
You state that it now works because you changed QObject::connect to connect. Now I'm not 100% on this but I believe the reason for this is that by calling connect, you are calling the method associated with an object which is part of your application. i.e. it's like doing this->connect(...). That way, it is associated with an existing object - as opposed to calling the static method QObject::connect which doesn't know anything about your application.
Sorry if that's not clear, hopefully I got the point across!
Using QObject::connect() and connect() is same in this context. I believe
QObject::connect(ui->webView,SIGNAL(linkClicked(QUrl)),
MainWindow,SLOT(linkClicked(QUrl)));
was called from a function inside MainWindow class. That is why when you tried
connect(ui->webView,SIGNAL(linkClicked(const QUrl)),
this,SLOT(linkClicked(const QUrl)),Qt::DirectConnection);
it works. Notice the difference that make it work - the third parameter. You used this in the second snippet, where as you used MainWindow in the first snippet.
Read this to know how signals and slots mechanism works and how to properly implement it.
I changed QObject::connect to only connect and it works.
So this code works:
connect(ui->webView,SIGNAL(linkClicked(const QUrl)),this,SLOT(linkClicked(const QUrl)),Qt::DirectConnection);
But I don't know why?