Qt how to connecto Line Edit to progress bar - c++

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.

Related

Is there a way to connect a QSlider and a QLineEdit object to each other?

I'm trying to connect a Slider and LineEdit widget together so that when one is changed the other will match this value.
I'm struggling since lineEdit takes strings and Slider takes ints. I already used setValidator on the lineEdit so that only ints can be entered.
I tried using the old signals and slots syntax with no luck using a couple different methods from a quick Google search.
connect(textbox, SIGNAL(textEdited(QString)),slider,
SLOT((QString)));
Should I be using a different widget entirely than LineEdit?
Use the lineEdit() method of QSpinBox():
connect(textbox, &QLineEdit::textEdited, slider->lineEdit(), &QLineEdit::setText);
I'm using stackoverflow firsty to answer others' question,Hahaha.
The better binding signal for QSlider is QSlider::sliderMoved, and do not bingding QSlider::valueChanged, otherwise they will conflict, maybe you can try it.
Binding QLineEdit::textChanged signal for QLineEdit.
code here:
connect(ui->horizontalSlider,&QSlider::sliderMoved,this,[=]{
int val=ui->horizontalSlider->value();
//You can process the variable val here.....
ui->lineEdit->setText(QString::number(val));
});
connect(ui->lineEdit,&QLineEdit::textChanged,this,[=]{
int val=ui->lineEdit->text().toInt();
//You can process the variable val here.....
ui->horizontalSlider->setValue(val);
});

C++ Qt: is it possible to create a sort of template slot?

I'm new to Qt and not a C++ expert so please bear with me with this one.
I'm working on an application that has 12 different QPushButtons, but all of them perform very similar actions: they grab some value from a map and then use it to set the style for that button:
void MainWindow::on_btn01_clicked(){
QString img=images["btn01"];
ui->btn01->setStyleSheet("#btn01{ background-image: url(://" + img + ") }");
}
For each one of the 12 buttons I have to create a slot that only differs in the button being used. So it looks a bit weird to create 12 functions that are almost identical.
Is there a better way to do this?
Generally, there are several approaches I've seen used:
The preferred method: lambda expressions.
If you're using modern C++ (C++11 or newer), you can use a lambda function to get the exact effect you described.
I'd expect the resulting code to look something like this:
foreach( QPushButton * button : buttons ) {
connect( button, &QPushButton::clicked, [button, &images]() {
button->setStyleSheet( QString( "{ background-image: url(://%1) }" )
.arg( images[button->objectName()] ) );
});
}
See "Qt Slots and C++11 lambda" for more guidance on how to write lambda functions with Qt.
A dirtier way: QObject::sender().
Qt lets you use QObject::sender() within a slot to get a pointer to the object that invoked it. This has been a widely used approach for many years, but there are limitations, as described in the Qt documentation:
Warning: As mentioned above, the return value of this function is not valid when the slot is called via a Qt::DirectConnection from a thread different from this object's thread. Do not use this function in this type of scenario.
See "How to get sender widget with a signal/slot mechanism?" for more information.
Obsolete code: QSignalMapper.
There's a QSignalMapper class that will let you associate a signal with a bit of data, like a string, to then connect to a slot that uses this parameter. This used to exist as a convenience class in Qt but is being phased out because the lambda methodology makes it pointless.
If you need to update code that uses QSignalMapper to remove it, this tutorial is a reasonable starting point.
You can try one more simple method, that is set the QPushButton's object name respectively, and check the Object name in your slot and use that string. This saves you a lot of code.
Ex:
QPushButton 1 object name is set as button->setObjectName("btn01"); and respectively you can set the other names of the buttons and in your slot you could do some thing like this
void MainWindow::on_button_clicked(){
QPushButton* btn=qobject_cast<QPushButton*>(sender());
QString name=btn->objectName();
QString img=images[name]; btn->setStyleSheet("#" + name + "{ background-image: url(://" + img + ");
}
and then connect all your QPushButtons to this slot

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.

How to use signal to execute any function with arguments?

Suppose I have a QPropertyAnimator animating (moving), say, a button - slightly to the left over the course of 10 seconds.
When the button reaches its destination on the other side of the window it should change its text to "banana" using the QLineEdit::setText() function.
If the QLineEdit::setText() function is issued directly after the animation start;
QPropertyAnimator *animator = new QPropertyAnimator(someButton, "pos");
animator->setDuration(10000);
animator->setStartValue(*current position of the button*);
animator->setEndValue(*current position of the button with x-100*);
animator->start();
QLineEdit::setText(QString("Banana"));
The text changes before it has the chance to start moving. Luckily, QPropertyAnimator emits a signal when the animation is completed - aptly titled finished().
One would like to just be able to:
connect(animator, SIGNAL(finished()), someButton, SLOT(setText("Banana")));
But since you can't pass an argument to a slot that won't work.
How do I change the text after the animation is complete without creating different "proxy" functions (slots) to do it without arguments?
As already others told, you should use lambda, in your case,
connect( animator, &QPropertyAnimator::finished, [&]()
{
m_lineEdit->setText( QString("Banana") );
} );

Connect signals to slots with constant values

To connect signals to slots, as far as I know, the parameters of the signal need to match the parameters of the slot. So for example:
connect(dockWidget->titleBarWidget(), SIGNAL(closeButtonClicked()), ui->sideControls, SLOT(closeDockWidget()));
But what if I want to have a signal call a slot that has a different amount of parameters, but always pass a constant value into the slot. For example, using the above piece of code:
connect(dockWidget->titleBarWidget(), SIGNAL(closeButtonClicked()), ui->sideControls, SLOT(setDockWidget(false)));
Or in other words, whenever the button is pressed, it calls the setDockWidget() function with the false parameter. Is this possible?
You can use lambda with desired call with constant argument. Example:
connect(obj, &ObjType::signalName, [this]() { desiredCall(constantArgument); });
More about new connect syntax: https://wiki.qt.io/New_Signal_Slot_Syntax.
No, it is not possible. You are only allowed to connect slots with less or equal argument count, than in corresponding signal. (see documentation)
You have to create proxy slot, that will call desired one.
In a way, yes, you can. But it's not very powerful : just declare the setDockWidget this way :
[virtual] void setDockWidget(bool state=false) ;
And declare the connection this way :
connect(emitter, SIGNAL(closeButtonClicked()), receiver, SLOT(setDockWidget()));
setDockWidget called without arguments take the default ones.