QT How to create custom slot? [duplicate] - c++

This question already has an answer here:
Qt, no such slot
(1 answer)
Closed 7 years ago.
I'm creating my first GUI App in QT, I'm newbie at it.
This application is supposed to count calories for me with little more options than webapps offer me.
In my program I got 4 lineedits :
lineEdit_Carbs
lineEdit_Fats
lineEdit_Protein
lineEdit_Calories
I want to do like "Realtime counter", if user provides value to any of the 3 cells, carbs,fats,proteins it shows how many calories is it already.
I tried to do this
connect(ui->lineEdit_Carbs,SIGNAL(textChanged(QString)),ui->lineEdit_Calories,SLOT(setText(CALORIE_COUNT(ui->lineEdit_Carbs->text(),ui->lineEdit_Fats->text(),ui->lineEdit_Proteins->text()))))
CALORIE_COUNT function takes 3 arguments, 3 QStrings, returns calculated QString containing the calories.
I would have to do this connection 3 times, for each lineEdit containing macronutrient.
But this seem to not work because
QObject::connect: No such slot QLineEdit::setText(CALORIE_COUNT(ui->lineEdit_Carbs->text(),ui->lineEdit_Fats->text(),ui->lineEdit_Proteins->text())) in ..\CalcProto\mainwindow.cpp:22
It says there is no such slot.
How should I create slot to make it work?

connect(ui->lineEdit_Carbs,
SIGNAL(textChanged(QString)),
this,
SLOT(intermediateSlot()));//SLOT can ignore incoming arguments
private Q_SLOTS:
intermediateSlot()
{
QString calorie = CALORIE_COUNT(ui->lineEdit_Carbs->text(),
ui->lineEdit_Fats->text(),
ui->lineEdit_Proteins->text());
ui->lineEdit.setText(calorie);// you can emit a new signal here
// carring calorie and connect it to
// ui->lineEdit, which is more Qt-ish
}

You maybe can subclass QLineEdit and reimplement the setText() method, but I am not sure you can, since it not seems to be declared as virtual
What about connecting all the QLineEdit textChanged(QString) to the the same slot and do all the work in it ?
Something like
connect(ui->lineEdit_Carbs,SIGNAL(textChanged(QString)), UpdateCalc);
connect(ui->lineEdit_Calories,SIGNAL(textChanged(QString)), UpdateCalc);
connect(ui->lineEdit_Fats,SIGNAL(textChanged(QString)), UpdateCalc);
connect(ui->lineEdit_Proteins,SIGNAL(textChanged(QString)), UpdateCalc);
where the UpdateCalc slot do all the calculations ?
Eventually you can add a timer to add a little delay to the execution so if you insert something with more than one char, you don't fire the event every time.

Related

Signals from delegate [duplicate]

This question already has answers here:
Passing an argument to a slot
(6 answers)
Closed 6 years ago.
I started working on a project that requires the using of the TableView. My table has 3 columns and the last column has a comboBox. Using the Delegate I managed to set the comboBox and to retrieve a signal when the index status of the comboBox changes. The problem is I can not identify from witch comboBox the signal is emited from.
If I signal to the mainWindow the QString of the comboBox this seems to be very bad. I was thinking at a solution to insert into the comboBox from each line the index of the row. Something like row + name.
I initiate the connection using the advice from another post, such like:
signals:
void boxDataChanged(const int & str);
In create editor:
QComboBox * editor = new QComboBox(parent);
editor->addItem("This");
editor->addItem("is");
editor->addItem("nice");
connect(editor, SIGNAL(currentIndexChanged(int)), this, SIGNAL(boxDataChanged(int)));
return editor;
And called like:
connect(mydelegate, &Delegate::boxDataChanged, [=](const int & str)
{
qDebug() << str;
});
This is working nice but I also need to know from witch row this is comming.
The problem is I can not identify from witch comboBox the signal is
emited from.
You can use QObject::sender to get the sender of the signal.
It will return a QObject that you can cast into the desired type.

QT Signals & slots in diffrent class

My program has 2 classes. One of them is MainWindow and another is Calc.
In main window I use automatic generated function on_PushButton_clicked. This function should send two values: double & char to function in Calc.
first:
void MainWindow::on_OneButton_clicked(){
QObject::connect(ui->ZeroButton , SIGNAL(clicked()), this, SLOT(...)) );
ui->TextEdit->insertPlainText("1");
}
second :
void Calc::Add(double val, char oper){
//compute something
}
It's my first app with Qt and I do not know how can I connect them. I've searched similar question on this forum, but can't found.
Sorry if i'm wrong.
First of all, you have to well understand what signal/slot mecanism is, and what you are doing.
Signal/slot mecanism is a Qt concept to link a function (signal) to another function (slot). To "make a link" between a signal and a slot, you have to connect them using QObject::connect(...).
When you use automatic generated function on_PushButton_Clicked() with Qt designer, you, in fact, "make a link" between the signal clicked() emitted when the pushButton is clicked, with a slot on_PushButton_Clicked(). However, the connection between this signal and this slot doesn't appear in your code so it may be confusing and that's why I'm pointing it out.
When you write this:
void MainWindow::on_OneButton_clicked(){
QObject::connect(ui->ZeroButton , SIGNAL(clicked()), this, SLOT(...)) );
ui->TextEdit->insertPlainText("1");
}
You create a connection with zeroButton when clicked and a slot, each time you clic on your button. As a connection is valid till an object is destructed, if you clic again on your pushButton, you'll have a second connection between zeroButton when clicked and your slot.
A better way to create connection is to use connect(...) function when you create your object (mainWindow in your case).
To make it simple for your calculator, you can create 9 buttons for digits, 4 buttons for operators, and 1 button to compute everything.
In your mainwindow constructor, you could have something like:
connect(ui->pushButton1, SIGNAL(clicked()), this, SLOT(onPushButton1Clicked()));
.... // Every other signal for each button
connect(ui->pushButtonEqual, SIGNAL(clicked(), this, SLOT(onPushButtonEqualClicked());
And in your body
void MainWindow::onPushButton1Clicked()
{
// concatenate current value + 1
ui->textEdit->insertPlainText(ui->textEdit->toPlainText() + "1");
}
void MainWindow::onPushButtonEqualClicked()
{
// check textedit content (need a digit + operator + digit)
...
// compute result
...
// write result in TextEdit
...
}
I hope it will help a little bit ;)

How to determine which widget triggered the slot function?

I have an array of 10 objects, each having 8 parameters, all represented in GUI. I'd rather not have 80 slots defined; I'd much prefer to have 1 slot handling all the GUI triggered changes:
// Connect 10 Term objects
for( int n = 0; n < m_MaxTerms; ++n )
{
// Connect several checkboxes for the nth Term item
connect(m_Term[n].m_CD.GetData(), SIGNAL(clicked(bool)), this, SLOT(UpdateTerm()));
// Connect several edit fields for the nth Term item
connect(m_Term[n].m_Volume.GetData(), SIGNAL(editingFinished()), this, SLOT(UpdateTerm()));
...
}
When UpdateTerm() is called I need to update the corresponding data based on the changes in the widget that triggered it. But how could I tell, from within UpdateTerm(), what widget triggered it? One way to solve the problem is to update data from all widgets when the slot is triggered by any of them. However, this is very inefficient; updating only the changed item would be much preferred.
Thus the question: is it possible from the slot function to determine which of the widgets triggered it? What would be the cleanest method of doing so?
You can use the QObject::sender() function to determine which object emitted the signal. This function is documented here.

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!

How to issue signal each time a row is edited in QListWidget?

class genericTaskList : public QListWidget
{
Q_OBJECT
public:
QListWidgetItem *defaultText;
genericTaskList (QWidget *parentWidget)
{
setParent (parentWidget);
setFixedSize (445, 445);
defaultText = new QListWidgetItem ("Double click here to compose the task");
defaultText->setFlags (defaultText->flags () | Qt :: ItemIsEditable);
insertItem (0, defaultText);
QObject :: connect (this, SIGNAL (currentRowChanged (int)), this, SLOT (addDefaultText (int)));
}
public slots:
void addDefaultText (int rr)
{
std::cout << "\ndsklfjsdklfhsdklhfkjsdf\n";
insertItem (++rr, defaultText);
}
};
This code is supposed to issue a signal each time the row gets edited.
After I call "insertItem" in the constructor, the signal is issued.
But, that's it. It never gets issued after that - no matter how many times I edit the row.
What am I missing?
At first it seems like QListWidget::itemChanged is the way to go, but soon you run into a problem: the signal is sent for everything - inserts, removes, changing colors, checking boxes, etc! So then you end up trying to put in flags and filter everywhere by intercepting various signals to find out if editing was the actual event. It gets very messy.
There is also QAbstractItemModel::dataChanged , which would seem like a good solution. It even has a parameter "const QVector& lstRoles" so you could scan for Qt::EditRole and see if it was really edited. Alas, there's a catch - it gets called for everything just like QListWidget::itemChanged and unfortunately, for QListWidget anyway, the roles parameter is always empty when it's called (I tried it). So much for that idea...
Fortunately, there's still hope... This solution does the trick! :
http://falsinsoft.blogspot.com/2013/11/qlistwidget-and-item-edit-event.html
He uses QAbstractItemDelegate::closeEditor, but I prefer using QAbstractItemDelegate::commitData.
So make a connect like so...
connect(ui.pLstItems->itemDelegate(), &QAbstractItemDelegate::commitData, this, &MyWidget::OnLstItemsCommitData);
Then implement the slot like this...
void MyWidget::OnLstItemsCommitData(QWidget* pLineEdit)
{
QString strNewText = reinterpret_cast<QLineEdit*>(pLineEdit)->text();
int nRow = ui.pLstItems->currentRow();
// do whatever you need here....
}
Now you have a slot that gets called only when the list item's text has been edited!
currentRowChanged indicates the row selection has changed, not the content of the row. Perhaps you want to use currentTextChanged or itemChanged instead.
The reuse of the word current and changed in the QT docs is quite confusing.
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.
So even if it will emit the signal I think you should better to add newly created Item.
And when do you want the new row to be inserted ? -
as soon as item is double clicked or finishing edit - they differ.