Signal and slot for multiple widgets - c++

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

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.

Map QWidget to variable

The idea was to connect QWidget with a variable so that when text changes on a widget it will be also changed in a variable.
And do this with just one line like this
WidgetMapper::connect(ui->lineEdit, SIGNAL(textChanged(QString)), someClass.var);
which would connect for example QLineEdit with a variable.
1) This would display var in a lineEdit
2) when lineEdit fires an textChanged(QString) signal - WidgetMapper would convert this QString to correct mapped type with stringstream and write it to var.
But i dont really know templates that well, and dont know if it is possible at all.
I dont think it is possible to use one WidgetMapper for every type, so i also tried creating separate instances for each type (WidgetMapper<int> mapper;) which would still be betten then writing setters and onTextChangedSlots for each QLiteEdit but i could not figure out how to make it work as well (converter part still could not figure out the correct type).
WidgetMapper is using QSignalMapper to map signal to QWidget, and it worked fine, the part i have troubles with - is converting QString to template variable.
So is it possible? And if yes how could i do this? Or maybe there already a solution for this problem? (Somehow use QDataWidgetMapper with a class that contains variables maybe?)
First of, connecting the variable would do nothing else than calling some function if it were possigle.
Second try using QSignalMapper, this way you could use a single slot for all widgets, given you keep their pointers in an array with the index being the signal(int) emitted by the SignalMapper. This way your slot can just use MyWidgetArray[i]->text().

How to tell when a QPushButton is clicked in a QButtonGroup

In my project, I have 40 QPushButtons all put into a QButtonGroup like this:
QButtonGroup* group = new QButtonGroup(this);
group->addButton(ui->slot_0);
group->addButton(ui->slot_1);
//...
group->addButton(ui->slot_38);
group->addButton(ui->slot_39);
Each button is a QPushButton that I made checkable. That way only one button can be checked at a time. All works great, but how can I "make a slot" when one of the buttons becomes checked? I don't want to have 40 different slots, one for each button all to end up doing essentially the same thing. Is there any way I can just use the QButtonGroup I put them in?
As Jamin and Nikos stated: you should create your own slot to handle the signal emitted by QButtonGroup. It could be something like this:
In the header file:
public slots:
void buttonWasClicked(int);
In the *.cpp file:
void MainWindow::buttonWasClicked(int buttonID)
{
cout << "You have clicked button: " << buttonID << endl;
}
And in the code responsible for creation of the MainWindow (i.e. in constructor but not necessairly) there should be this line:
connect(group, SIGNAL(buttonClicked(int)), this, SLOT(buttonWasClicked(int)));
Be aware that since Qt5 the connect syntax has changed. The syntax I used here is from Qt4. It still works but is deprecated now (for more information please refer to New Signal Slot Syntax in Qt 5). Moreover I would suggest going through QButtonGroup class reference as there are other available signals which could suit your needs better than the one I've chosen.
BR
The documentation for QButtonGroup shows a QButtonGroup::buttonClicked() signal - have you already tried that one?
The signal comes in two variants - one that gives the QPushButton as a parameter (as a QAbstractButton), and one that gives the ID of the button in the group.
You can use connect() to setup signal and slot connections in your C++ code.
Sometime during the initialization of your window's class (perhaps in the constructor), call this:
connect(myButtonGroup, SIGNAL(buttonClicked(QAbstractButton*)), this, SLOT(theSlotThatYouWrite(QAbstractButton*));
Where myButtonGroup is probably this->ui->nameOfTheButtonGroup, and theSlotThatYouWrite is a function that you write in your own code, that belongs to your window's class, that returns void and takes a signal QAbstractButton* as a parameter (since that's what this specific signal gives as an argument).
Make sure theSlotThatYouWrite is under the label "private slots:" or "public slots:" in your class's interface.
Here's a screenshot of actual usage of some signals and slots in my own code.
Signals and Slots is something very important to learn, but can be bit of a hill to climb when first trying to understand it!

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.)

Signals and slots QT

I have asked a number of different questions now all regarding one main issue in my program and still not solved it at all, I'm using threading to keep my UI from locking up, but basically it still does because apparently you can't do UI stuff in threads.
So I've been told to use custom signals and slots (not that any examples were given).
So from the documentation I've read I came up with this code:
.h
signals:
void paint_signal(double x, double y);
.cpp
connect(this,SIGNAL(paint_signal(double x, double y)), this, SLOT(PaintSomething(x,y)));
the Paintsomething function is within the same class as all of this....
thread:
*future2 = QtConcurrent::run(this, &GUI::paintAll);
paint all emits the paint_signal and passes 2 doubles
emit paint_signal(x, y);
but I get this error which I just don't understand at all
connect: No such signal GUI::paint_signal(double x, double y)
connect(this,
SIGNAL(paint_signal(double, double)),
this,
SLOT(PaintSomething(x,y)));
Remove parameter names and it should work. If this one doesn't work this one will:
connect(this,
SIGNAL(paint_signal(double, double)),
this,
SLOT(PaintSomething(double,double)));
Let me know if this works out for you :)
Update
The idea is that you cannot use the UI in a thread, instead you emit signals from the thread to the UI. Because this answer probably gets you back to the beginning (and possibly a new question) here is a working example of how to emit signals from threads:
QT Signals to UI in a thread
Floris Velleman's answer is ok, however by using the new signal slot syntax, you can catch errors during compile time and get rid of the redundant paranthesis.
Old Syntax:
connect(this,
SIGNAL(paint_signal(double, double)),
this,
SLOT(PaintSomething(double,double)));
New Syntax:
connect(this,
&SenderClass::paint_signal,
this,
&ReceiverClass::PaintSomething);