Correct C++ syntax in Qt "connect"? - c++

I am learning how to use connect in Qt.
I have an idea how it works when connecting widgets in current object.
My problem is - I do not fully understand C++ syntax when connecting two objects.
My current learning test task is to pass item selected in list to list_2 using C++ code - in current object. (I know how to implement that using QtDesigner - but I want to learn using code)
QListWidgetItem item;
connect(ui->list,
&QListWidget::itemClicked(QListWidgetItem &item),
ui->list_2,
&QListWidget::addItem(&item));
The above code gives me two errors and I need help to IDENTIFY what is wrong with my C++ syntax.
/media/f/QT/Qt/QT/qtconnectivity/examples/bluetooth/CAT_BT_18112020/device.cpp:127: error: expected primary-expression before '&' token
&QListWidget::itemClicked(QListWidgetItem &item),
/media/f/QT/Qt/QT/qtconnectivity/examples/bluetooth/CAT_BT_18112020/device.cpp:129: error: cannot call member function 'void QListWidget::addItem(QListWidgetItem*)' without object
&QListWidget::addItem(&item));
^
Thank you
I like to add / edit / clarify the post.
It would be helpful to start with knowing the convention / symbols in this C++ connect code.
What are the piece parts [=](){...} of "lambda" syntax in English?
connect(action, &QAction::triggered, engine,
[=]() { engine->processAction(action->text()); });
Perhaps help me by applying similar to my initial connect code.

The correct syntax for the connect statement should be
connect(list_widget_1,
&QListWidget::itemClicked,
list_widget_2,
QOverload<QListWidgetItem*>::of(&QListWidget::addItem));
Because addItem() has 2 overloads, QOverload must be used
QListWidget::addItem(const QString &label)
QListWidget::addItem(QListWidgetItem *item)
But you don't want to do this, since the documentation specifically said that:
Warning: A QListWidgetItem can only be added to a QListWidget once. Adding the same QListWidgetItem multiple times to a QListWidget will result in undefined behavior.
Instead you should do something like this
connect(list_widget_1,
&QListWidget::itemClicked,
[list_widget_2](QListWidgetItem *item)
{
list_widget_2->addItem(item->clone());
});
Explanation for the lambda part:
Inside the square brackets is the capturing part. In the following body of the lambda, I need to use list_widget_2, so I need to capture it.
Inside the parentheses is the place for the parameters. This part is like normal functions. Since itemClicked() passes a QListWidgetItem *, I will take it as parameter for the lambda.
Inside the curly braces is the lambda body. This part is like normal functions.
More information on lambda in the documentation

Related

Qt how to connecto Line Edit to progress bar

I am very new to QT and C++, I am trying to connect Line edit to progress bar so when I enter some integer value to the Line Edit, progress bar will show it. I could not achieve it. This is what I was trying:
connect(ui->batterycapacity,&QLineEdit::textChanged, ui->progressBar,ui->progressBar->setValue(ui->batterycapacity->text().toInt()));
or this:
connect(ui->batterycapacity,&QLineEdit::textChanged, ui->progressBar,ui->progressBar->&QProgressBar::setValue(ui->batterycapacity->text().toInt()));
batterycapacity is my Line Edit. How can I connect those 2 together? Thanks beforehand.
You're close. As the signal's argument differs from the slot's argument you need to adapt it with toInt, but you cannot simply stick arbitrary code in an argument and expect C++ to execute it when the signal changes.
You need to wrap your snippet in a lambda expression:
connect(ui->batterycapacity, &QLineEdit::textChanged, ui->progressBar,
[=](const QString& text) {
ui->progressBar->setValue(text.toInt()));
});
The lambda will receive the argument of the textChanged signal and pass that to the setValue method.
The [=] bit at the front tells the compiler to capture the value of ui by value so it is accessible inside the lambda.

Qt connect doesn't recognize with lambda expression

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.

Signal and slot for multiple widgets

I have three pushbutton widgets in my class and i want to connect the clicked signals from all of the three to one slot. Here is what my syntax looks like:
QObject::connect(PtrLineedit1, SIGNAL(Clicked()), this, SLOT(myslot()));
QObject::connect(PtrLineedit2, SIGNAL(Clicked()), this, SLOT(myslot()));
QObject::connect(PtrLineedit3, SIGNAL(Clicked()), this, SLOT(myslot()));
But the above syntax is not working. And the above syntax i am using in one of my WizardPage class. this Wizard has three pages, and in one of the page(class) has three pushbuttons and in this class constructor i am trying to achieve. I have used "clicked()" too, but no luck
First of all, there is no signal "Clicked", but there is "clicked" - the lowercase one.
Second - it's better not to use the macros SIGNAL and SLOT - they are error prone, like in your case. If you look inside them, they are generating a string, which could not be checked by compiler. Instead better to use following syntax:
QObject::connect(PtrLineedit1, &LineEditClass::clicked, this, &ThisClass::myslot);
Cause if you will write then:
QObject::connect(PtrLineedit1, &LineEditClass::Clicked, this, &ThisClass::myslot);
It would produce the error during compilation, in case when LineEditClass::Clicked is not defined. This would protect you from typos.
UPD: As eventually I've found another your question which faces issue relevant to this one, I've updated this answer with more details, which might be helpful for others.
In case of overloaded methods, you must explicitly tell compiler which one should be used - for example we have following:
void QComboBox::currentIndexChanged(int index)
void QComboBox::currentIndexChanged(const QString &text)
thus the &QComboBox::currentIndexChanged could be resolved ambigously, and you will get the compilation error. To fix it you need to explicitly tell what are the arguments of the function you want to connect to:
QObject::connect(comboBox, static_cast<void(QComboBox::*)(int)>(&QComboBox::currentIndexChanged), this, &ThisClass::myComboBoxSlotWithIntArg);
or
QObject::connect(comboBox, static_cast<void(QComboBox::*)(const QString &)>(&QComboBox::currentIndexChanged), this, &ThisClass::myComboBoxSlotWithStringArg);

QT - How to retrieve QVariant Values from combobox?

I'm using QVariant to store a object inside of a Qcombobox, This appears to work fine. This is the implementing code:
Add type to QVariant in header:
Q_DECLARE_METATYPE(CDiscRecorder*)
pDiscRecorder Casted as CDiscRecorder:
CDiscRecorder* pDiscRecorder = new CDiscRecorder();
Then stored in the combobox
ui->cbDrives->addItem(QString::fromWCharArray(strName), QVariant::fromValue(pDiscRecorder));
The problem arises when I try to pull it out:
CDiscRecorder* discRecorder = this->ui->cbDrives->itemData(index).value<CDiscRecorder*>;
I receive the error:
error C3867: 'QVariant::value': function call missing argument list; use '&QVariant::value' to create a pointer to member
I tried to implement the hint in the error code to no avail, I have followed the thread Add QObject in the combo box of Qt to implement this behavior, how can get my object back ?
Thanks
The compiler is giving you the hint that the argument list is missing - all you should need to do is add the brackets to tell it that you're trying to call the function. So change it to
CDiscRecorder* discRecorder = this->ui->cbDrives->itemData(index).value<CDiscRecorder*>();
And it should work. That's quite a long line, might be cleaner to break it out
QVariant variant = this->ui->cbDrives->itemData(index);
CDiscRecorder* discRecorder = variant.value<CDiscRecorder*>();

Standard and "exotic" icons

I'm trying to use the standard icons in Qt for a QToolButton but I have a problem. My code is:
m_buttonZoomPlus->setIcon(QStyle::standardIcon(QStyle::SP_DesktopIcon));
I get the error message :
cannot call member function 'QIcon QStyle::standardIcon(QStyle::StandardPixmap, const QStyleOption*, const QWidget*) const' without object
What does it mean? Do I Have to create an empty QStyle object and call the standardIcon function on it?
Besides, I found a list of standard icons here: http://doc.trolltech.com/main-snapshot/qstyle.html#StandardPixmap-enum
Is this list exhaustive or are there other standard icons? I'm looking for instance for a zoom-in/out icon and I've not yet been able to find it.
Thank you very much for you help.
It means standardIcon is not a static method so you can't call it that way. You need to construct a QStyle and initialize it appropriately then you can use that method to get a specific icon.
Edit: Jeremy is right. If you aren't changing the style or defining your own style you can simply use the following:
QApplication::style()->standardIcon(QStyle::SP_DesktopIcon);
Reference: http://doc.qt.io/qt-5/qstyle.html#standardIcon