connecting signals and slots with different relations - c++

First of all I'd say I'm a noob to GUI programming. I use Qt 5.4.
I came up with this code while watching voidRealms videos.
connect(ui->horizontalSlider,SIGNAL(sliderMoved(int)),ui->progressBar,SLOT(setValue(int)));
Obviously this connects slider movement with progressbar fill. This actually works like
progressbarfill <- slidermovement.
How can I make into a different relation? Like
progressbarfill <- (slidermovement)/2 or something like that.

You need to create new slot for that purpose.
But in C++ 11 and Qt 5 style you can use labmdas! It is very comfortable for such short functions.
In your case:
connect(ui->horizontalSlider, &QSlider::sliderMoved, this, [this](int x) {
this->ui->progressBar->setValue(x / 2);
});

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);
});

Qt signals and slots. Slider and progress bar

connect(ui->horizontalSlider, SIGNAL(valueChanged(int)),
ui->progressBar, SLOT(setValue(ui->horizontalSlider->value()-100)));
I tried to connect signals and slots when the value of slider for example is 30, the value of the progress bar should be 70 but nothing is changed, I can't find mistake.
Welcome aboard.
I am surprised that you want to do a calculation inside the connect. This is not how it works.
Please add a slot (method) like
void slotSetValue(int input)
{
ui-progressBar->setValue(100 - input);
}
and connect like
connect(ui->horizontalSlider,SIGNAL(valueChanged(int)), this,slotSetValue(int)));
Fine-tuning for your code may be needed.
ps. I recommend to use the Qt5-connects, which are compile-time-checked.
You normally do :
connect(ui->horizontalSlider, &QSlider::valueChanged,
ui->horizontalSlider, &QSlider::setValue);
but your logic is not correct because you are connecting a valueChanged with a setValue , that will crash your app since an overflow will happen...
on the other hand, connect used to only pipe signals and slots, you can not do math in the signals/functions involved in that, at least not like that... you will need a lambda or something similiar in the middle

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

Weird behavior when switching view between C++ and QML

I'm currently working on a project using Qt 5.0.2 on an embedded linux (ARM Cortex A9).
The main UI interface is developped in QML but I need to be able to hide this view to show a QWebView directly in C++.
I coded a simple view controller in c++ who hide()/show() the QML view and the many instances of QWebView.
The hiding/showing method work fine but when i show back the QML view, it's very instable. QML object are visible (or not visible :p) when they should not and the focus are buggy too. Object are draw in the wrong position too.
I try several methods :
-Initialize the focus/visible property of the differents objects everytime I show the QML view.
-use .setSource() everytime before showing the view
-try to update() the differents object thank to rootObject() before showing the view.
Did anyone have a tips to make the QML view functionnal again after a switch to a c++ view ?
thank.
there is probably a better way but,
you could probably do something like this (I have not tested this):
note: if the slot implementation is wrong (bad math) it will result in infinite recursion.
//this code could probably be in the constructor
real widthOverHeightRatio = 2;//set this value to what you want, or what it is when user first presses shift depending on the use case.
QObject::connect(this, SIGNAL(widthChange()), this, SLOT(onWidthChanged()));
QObject::connect(this, SIGNAL(heightChanged()), this, SLOT(onHeightChanged()));
//don't forget to define these slots in the header
//implemented slots
void MyClass::onWidthChanged()
{
if(width/height!=widthOverHeightRatio){
height = width/widthOverHeightRatio;
}
}
void MyClass::onHeightChanged()
{
if(width/height!=widthOverHeightRatio){
width = height*widthOverHeightRatio;
}
}

Is it possible to program function into Qt's SLOT() for QWidget or should use QSignalMapper?

In my Qt Application I am dynamically creating 'Questions' in QVBoxLayouts for a 'Questionnaire'. There are 3 types of Questions: Boolean, Text, & Radio.
When the user 'adds a question' to the questionnaire, they are presented with a QComboBox. When the index/text of this QComboBox is edited, I want to act upon the SIGNAL emitted.
I would like to have something like Java's (from an old Android Project):
button.setOnClickListener(new OnClickListener() {
public void onClick(View v) {
//Code to run...
}
});
Is it possible to have the same in Qt/C++ like:
connect(qvectorOfComboBoxes.at(qvectorOfComboBoxes.end()), SIGNAL(currentTextChanged(QString)),
this, SLOT(
void comboBoxTextChanged(QString newComboxBoxText)
{
//This doesn't work
} )) ;
I understand from another post on here the ideal approach is a QSignalMapper, but was hoping to perform the task in a manner similar to above.
Usually, I find my answers either on here or from a related Google search (I am probably searching the wrong thing as I don't know the name for this), and so was hoping somebody here could give me a yay or nay. Thanks
In Qt5 and using a C++11-enabled compiler, you can use lambdas as slots, as explained here:
connect(sender, SIGNAL(signal(QString)), [](QString newComboxBoxText) {
// add your code here
});
Otherwise, you can use sender() to query the QObject* which sent the signal, if this is enough information you need. To cast it to a QComboBox* please use qobject_cast<QComboBox*> and Q_ASSERT that it's not null. (You can't get a compile-time error that it was connected to some other type.)