C++ Qt: Connect a TextEdit with a Label - c++

In a Qt GUI I'm trying to connect a TextEdit with a label so that when the user types something, the label updates it's text. Here is what I've tried:
void MainWindow ::updatelabel()
{
ui->label->setText("Hello");
}
void MainWindow::changeTextColor()
{
QString textEdit = ui->textEdit->toPlainText();
QString label = ui->label->text();
connect(textEdit, SIGNAL(textChanged()), label, SLOT(updateLabel()));
}
This gives me an error though:
error: no matching function for call to 'MainWindow::connect(QString&, const char*, QString&, const char*)'
connect(textEdit, SIGNAL(textChanged()), label, SLOT(updateLabel()));
^
What am I doing wrong and how can I fix it? Thanks!

You have a few problems in your code. Here's changed code with comments explaining it:
// make sure updateLabel is declared under slots: tag in .h file
void MainWindow ::updatelabel()
{
// set label text to be the text in the text edit when this slot is called
ui->label->setText(ui->textEdit->toPlainText());
}
// this is a very suspicious method. Where do you call it from?
// I changed its name to better indicate what it does.
void MainWindow::initializeUpdatingLabel()
{
//QString textEdit = ui->textEdit->toPlainText(); // not used
//QString label = ui->label->text(); // not used
// when ever textChanged is emitted, call our updatelabel slot
connect(ui->textEdit, SIGNAL(textChanged()),
this, SLOT(updatelabel())); // updateLabel or updatelabel??!
}
A practical hint: when ever you use SIGNAL and SLOT macros, let Qt Creator to autocomplete them. If you type them by hand, and make a typo, you don't get a compile time error, instead there will be a runtime warning print about having no a matching signal/slot.
Or, assuming you are using Qt5 and C++11 capable compiler, you can use the new connect syntax, which will give you compiler error if you get it wrong. First add line CONFIG += C++11 to the .pro file, and then do the connect like this:
void MainWindow::initializeUpdatingLabel()
{
connect(ui->textEdit, &QTextEdit::textChanged,
this, &MainWindow::updatelabel);
}
Now if you for example actually have no updateLabel method, you get compile time error, which is much nicer than runtime message which you might not even notice. You could also replace the whole updatelabel method with a lambda, but that goes out of the scope of this question/answer.

You're connecting to the wrong textEdit and label variables in that method:
- connect(textEdit, SIGNAL(textChanged()), label, SLOT(updateLabel()));
+ connect(ui->textEdit, SIGNAL(textChanged()), this, SLOT(updateLabel()));
A QString is not a widget with signals and slots. You want the actual widget from ui, ui->textEdit, and this for the current class which contains updateLabel().
Edits: fix mistakes I made because I answered while tired.

Related

I want to use the QComboBox with an Event (Return) in QT

I have the following problem:
I'm using the QComboBox of QT to select a path by a Drop & Down.
It is working fine after I choose one of the list, the path is automatically update. But now if I want to edit the Path manually by type in a path, I get immediately a warning. So I know that this is happening cause of the argument:
QComboBox::currentTextChanged
So always if I'm going to change the path, for example by changing only one letter or select it by Drop & Down the "currentTextChanged" and a new function will be called.
For example the function:
nextstep()
So what I want to achieve is that if I'm going to select a path the function should be called normally. But if I'm going to type in a new path or editing the path manually I want that the function will be called after type "return".
You could subclass QComboBox and define a new signal in your class that's emitted only when the user types enter or when the index is changed.
To do that you must connect your new signal to QComboBox::lineEdit()'s returnPressed() or editingFinished() signals and to QComboBox::currentIndexChanged().
I chose editingFinished() but you can try the other one too.
All that is left is to connect nextstep() to currentTextSaved()
To use MyComboBox in the .ui files, you have to promote the existing QComboBoxes to it.
Here's the official documentation: https://doc.qt.io/qt-5/designer-using-custom-widgets.html
mycombobox.h
#ifndef MYCOMBOBOX_H
#define MYCOMBOBOX_H
#include <QComboBox>
class MyComboBox : public QComboBox
{
Q_OBJECT
public:
MyComboBox(QWidget *parent = nullptr);
signals:
void currentTextSaved(const QString &text);
};
#endif // MYCOMBOBOX_H
mycombobox.cpp
#include "mycombobox.h"
#include <QLineEdit>
MyComboBox::MyComboBox(QWidget *parent)
: QComboBox(parent)
{
connect(lineEdit(), &QLineEdit::editingFinished,
this, [&] () { emit currentTextSaved(currentText()); });
connect(this, QOverload<int>::of(&QComboBox::currentIndexChanged),
this, [&] (int index) { Q_UNUSED(index) emit currentTextSaved(currentText()); });
}
Here's an example: https://www.dropbox.com/s/sm1mszv9l2p9yqd/MyComboBox.zip?dl=0
This old post was useful https://www.qtcentre.org/threads/26860-Detecting-Enter-in-an-editable-QComboBox

Qt no such slot for method

I am trying to learn Qt (using CMake/c++). Here is piece of code that I wrote. I am trying to use connect functionality. There is no compiling error. I used also following command to re-generate moc file.
moc -o moc_SimulationRunner.cpp SimulationRunner.h
However I am still receiving this error while running my project:
QObject::connect: No such slot SimulationRunner::_OpenFileDialog(file_address)
my header file is:
class SimulationRunner : public QWidget
{
Q_OBJECT
public:
explicit SimulationRunner(QWidget *parent = nullptr);
private:
QGroupBox *createFirstExclusiveGroup();
private slots:
bool _OpenFileDialog(QLineEdit* i_line_edit, std::string = "");
};
and my cpp file is:
QGroupBox *SimulationRunner::createFirstExclusiveGroup()
{
QGridLayout *grid = new QGridLayout;
....
QLineEdit *file_address= new QLineEdit();
file_address->setPlaceholderText("File address");
QPushButton *file_address_button = new QPushButton("Browse...");
file_address_button ->setFixedWidth(75);
grid->addWidget(file_address, 0, 0, 1, 1);
grid->addWidget(file_address_button , 1, 1, 1, 1);
group_box->setLayout(grid);
QObject::connect(file_address_button , SIGNAL(clicked()), this, SLOT(_OpenFileDialog(file_address)));
return group_box;
}
bool SimulationRunner::_OpenFileDialog(QLineEdit* i_line_edit, std::string /* = "" */)
{
if (!i_line_edit)
return false;
QString filename = QFileDialog::getOpenFileName(
this,
"Open Document",
QDir::currentPath(),
"All files (*.*) ;; Document files (*.doc *.rtf);; PNG files (*.png)");
if (!filename.isNull())
{
qDebug() << "selected file path : " << filename.toUtf8();
}
i_line_edit->setText(filename);
return true;
}
The arguments (signature) of the signal and the slot have to match.
If you use the old string-based Syntax you have to define the arguments in the SIGNAL() and SLOT() macros. So you could connect for example like this:
QObject::connect(file_address_button, SIGNAL(clicked(bool)), this, SLOT(_ExampleSlotFunction(bool)));
You cannot connect to a slot with more or different arguments. However you can connect to a slot with fewer arguments, e.g. like this:
QObject::connect(file_address_button, SIGNAL(clicked(bool)), this, SLOT(_AnotherExampleSlotFunction()));
If you use the new QT5 Syntax (which is recommended because it should warn you already when compiling) you don't need to specify the arguments yourself:
QObject::connect(file_address_button, &QPushButton::clicked, this, &ExampleClass::_ExampleSlotFunction);
QObject::connect(file_address_button, &QPushButton::clicked, this, &ExampleClass::_AnotherExampleSlotFunction);
QT5 / C++11 workaround
To pass a different argument, you could connect a lambda function to the signal, in which you call the slot or function. So to pass your QLineEdit:
QObject::connect(
file_address_button, &QPushButton::clicked,
this, [file_address]() { _OpenFileDialog(file_address); }
);
Further explanations:
New Syntax
Default Arguments
You're misunderstanding the meaning of the argument in the connect.
the signature of your slot is
OpenFileDialog(QLineEdit*, std::string);
and the signature of your connect is
OpenFileDialog(QLineEdit*)
that's why you're getting the warning. You're not calling a function (so it can be resolved with the default parameter), you're pointing to a function, so the signature has to be the same.
Tip: unless you have to use Qt4, use the Qt5 connect syntax:
QObject::connect(file_address_button, &QPushButton::clicked, this, &SimulationRunner::OpenFileDialog);
for your specific case:
if you always pass file_address in your slot, then just remove the argument from the slot and use it directly in the body.
Otherwise, if you're using Qt4, the only workaround is to make an additional slot with the call with no object.
Qt4 way:
private slots:
void _dummySlot(){
_OpenFileDialog(file_address);
}
QObject::connect(file_address_button , SIGNAL(clicked()), this, SLOT(_dummySlot()));
Qt5 way, use lambda:
QObject::connect(file_address_button, &QPushButton::clicked, this, [this](){
_OpenFileDialog(address_name);
});

QSpinBox and QDoubleSpinBox do not call method on valueChanged

All i want to do is call a method when the value of a qspinbox and a doublespinbox are changed.
I do not need the actual value from the spinbox being changed, i just want it to trigger the calling of another method. Why does the code below not error or do anything at all? Not even call the method?
cpp
connect(uiSpinBox, SIGNAL(valueChanged()), this, SLOT(slotInputChanged));
connect(uiDoubleSpinBox, SIGNAL(valueChanged()), this, SLOT(slotInputChanged));
void ColorSwatchEdit::slotInputChanged()
{
qDebug() << "Im here";
}
header
public:
QSpinBox *uiSpinBox;
QDoubleSpinBox *uiDoubleSpinBox;
public slots:
void slotInputChanged();
Even if you do not use the data that carries the signal you must establish the signature in the connection:
connect(uiSpinBox, SIGNAL(valueChanged(int)), this, SLOT(slotInputChanged));
connect(uiDoubleSpinBox, SIGNAL(valueChanged(double)), this, SLOT(slotInputChanged));
But it is recommended that you use the new connection syntax as it would have indicated the error:
connect(uiSpinBox, QOverload<int>::of(&QSpinBox::valueChanged), this, &ColorSwatchEdit::slotInputChanged);
connect(uiDoubleSpinBox, QOverload<double>::of(&QDoubleSpinBox::valueChanged), this, &ColorSwatchEdit::slotInputChanged);
In addition to eyllanesc's answer, consider using the FunctionPointer syntax if possible, i.e.
connect(uiSpinBox, QOverload<int>::of(&QSpinBox::valueChanged), this, &YourClass::slotInputChanged)
and
connect(uiDoubleSpinBox, QOverload<double>::of(&QDoubleSpinBox::valueChanged), this, &YourClass::slotInputChanged)
this way the compiler can tell at compile time you if the connection cannot be resolved

Qt Change ComboBox2 based on ComboBox1

Hi I am fairly new to Qt scene and I'm having trouble updating my comboBox2 based on comboBox1 selection.
Everytime I make a change in comboBox1, my app crashed, saying access violation. It's probably very straightforward but here's my code: In this case, the initial comboBox1 has "Car" and "Food". Whenever I switch to "Food", I want my comboBox2 to populate the item "Egg".
Any idea what went wrong ?
main.h
class main:
{
Q_OBJECT
public:
main() {}
public slots :
private slots:
void onComboBoxIndexChanged();
private:
QComboBox* comboBox2;
void run();
};
main.cpp
void main::run()
{
QWidget *w = new QWidget();
QComboBox *comboBox1 = new QComboBox();
QComboBox *comboBox2 = new QComboBox();
comboBox1->addItem("Car");
comboBox1->addItem("Food");
connect(comboBox1, SIGNAL(currentIndexChanged(int)), this, SLOT(onComboBoxIndexChanged()));
...
}
void main::onComboBoxIndexChanged()
{
QComboBox* combo = dynamic_cast<QComboBox*>(sender());
if (combo == nullptr)
{
return;
}
comboBox2->addItem("Egg");
}
You didn't fix your typo correctly. There's three things I see wrong, and I would've thought the third one would prevent this from compiling.
First, main.h says that your class name is "main", but in main.cpp, your class is WIPGui. Clearly one of those files isn't the right one. I'm going to proceed assuming that your actual main.h file defines the WIPGui class, but otherwise looks the same.
Second, as Mike tried to point out, in your run function, you have this:
QComboBox *comboBox2 = new QComboBox();
That's creating a local variable in your "run" method; it is not assigning to your class member variable comboBox2. What you want is:
comboBox2 = new QComboBox();
Third, your connect statement shouldn't compile based on the code we're seeing:
connect(comboBox, SIGNAL(currentIndexChanged(int)), this, SLOT(onComboBoxIndexChanged()));
The "comboBox" variable doesn't exist anywhere in this code. If you've actually used "comboBox1" in the connect statement, but this is just another typo in the code you've presented here, then the connect statement is fine. If this is a cut-and-paste as-is, then I don't see how this compiles.
Assuming that you've used "comboBox1" in the connect statement, then the real problem is that you're never assigning to the member variable "comboBox2" and when your slot tries to use it, you get a crash.

Qt No matching function for call to mainWindow::connect()

I'm trying to connect a combo box value and a label such that when the combo box changes the label reflects that. I have googled my heart out trying to find an answer but, as of yet, nothing has worked; I still get the error:no matching function for call to mainWindow::connect(QComboBox*&, const char [38], QString*, const char [26])
I have tried QObject::connect, QWidget::connect and anything else dealing with Qt, but to no avail.
Creating a label that says the combo box value is not my final intention for the program. Rather, I wish to get it working with a simple label then change it to what I want it to display (thus the tempLabel).
mainwindow.h:
class MainWindow : public QMainWindow
{
public:
MainWindow();
private slots:
QString getClass(QComboBox *box);
};
mainwindow.cpp:
MainWindow::MainWindow()
{
QString qMathClassName;
QComboBox* mathClassCombo = new QComboBox;
QLabel* label = new QLabel(qMathClassName);
// omitting layout code...
connect(mathClassCombo, SIGNAL(currentIndexChanged(const QString &)),
&qMathClassName, SLOT(getClass(mathClassCombo)));
}
QString MainWindow::getClass(QComboBox *box)
{
return box->currentText();
}
Any help would be greatly appreciated!
You are connecting a signal to a slot with a different signature. You have to change your slot to something like
getClass(const QString &)
to match currentIndexChanged signal.
I think you need to read Qt's signals and slots documentation. Again, if you've already done so. Pay special attention to their examples.
I think that you had these misconceptions about Qt in C++:
That QLabel takes a reference to a QString, and that it will update its text when that string changes. It won't. QLabel will display the value of the string when you give it the string. That is the only time it will update.
That objects constructed on the stack will not be destroyed at the end of the function. They will not. At the end of the constructor, qMathClassName will be destroyed and any reference to it will become invalid. Thus, you'd not want to make a connection to it, even if you could.
That the third argument of QObject::connect is a pointer to a place to put the return value for the slot. It's not. The third argument is a pointer to the QObject on which to call the slot. The return value of a slot is unused for any calls made to it via QObject::connect.
That you can bind values to slots in your connection. Unfortunately not. Within the SLOT macro, you must put the function signature of the slot. You may not reference any variables. The arguments section must have only class names. That is SLOT(getClass(QComboBox*)), not SLOT(getClass(mathClassCombo)).
The simplest way to ensure the contents of a combo box are displayed in a label are this:
QComboBox* mathClassCombo = new QComboBox;
QLabel* tempLabel = new QLabel;
connect(mathClassCombo, SIGNAL(currentIndexChanged(const QString&)),
tempLabel, SLOT(setText(const QString&)));
If you want to do something more complicated, I recommend just making a slot on your window that can handle those complications. For example:
mainwindow.h:
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
MainWindow();
private slots:
void updateLabelText(const QString& className);
private:
QComboBox* mathClassCombo;
QLabel* tempLabel;
}
mainwindow.cpp:
MainWindow::MainWindow()
{
mathClassCombo = new QComboBox;
tempLabel = new QLabel;
// omitting layout code...
connect(mathClassCombo, SIGNAL(currentIndexChanged(const QString&)),
this, SLOT(updateLabelText(const QString&)));
}
void MainWindow::updateLabelText(const QString& className)
{
QString newLabelString = className + " is the best class ever!";
tempLabel->setCurrentText(newLabelString);
}