Using a lambda in a connection
-
Hi all,
Please take a look at these files:
List.h:
#ifndef LIST_H #define LIST_H #include <QMainWindow> #include "Task.h" #include <QVector> class QLabel; class QPushButton; class QHBoxLayout; class QVBoxLayout; class List : public QMainWindow { Q_OBJECT public: explicit List(QWidget *parent = nullptr); void updateStatus(); ~List(); public slots: void addTask(); void removeTask(Task*); void taskStatusChanged(); private: QVector<Task*> mTasks; QLabel* statusLabel; QPushButton* addTaskButtun; QHBoxLayout* hBox; QVBoxLayout* vBox; }; #endif // LIST_H
List.cpp:
#include "list.h" #include <QPushButton> #include <QLabel> #include <QHBoxLayout> #include <QVBoxLayout> #include <QString> #include <QInputDialog> #include <QLineEdit> List::List(QWidget *parent) : QMainWindow(parent), mTasks() { statusLabel = new QLabel(tr("Status: 0 todo / 0 done")); addTaskButtun = new QPushButton(tr("Add task")); hBox = new QHBoxLayout; hBox->addWidget(statusLabel); hBox->addStretch(); hBox->addWidget(addTaskButtun); vBox = new QVBoxLayout; vBox->addLayout(hBox); vBox->addStretch(); QWidget *widget = new QWidget; widget->setLayout(vBox); setCentralWidget(widget); connect(addTaskButtun, &QPushButton::clicked, this, &List::addTask); updateStatus(); } //************************************************ void List::addTask() { bool ok; QString name = QInputDialog::getText(this, tr("Add Task"), tr("Task name"), QLineEdit::Normal, tr("Untitled task"), &ok); if(ok && !name.isEmpty()) { Task* task = new Task(name); connect(task, &Task::statusChanged, this, &List::taskStatusChanged); mTasks.append(task); vBox->addWidget(task); updateStatus(); } } //********************************************* void List::removeTask(Task* task) { mTasks.removeOne(task); vBox->removeWidget(task); delete task; updateStatus(); } //************************************** void List::taskStatusChanged() { updateStatus(); } //************************************ void List::updateStatus() { int completedCount = 0; for(auto t: mTasks) if(t->isCompleted()) completedCount++; int todoCount = mTasks.size() - completedCount; statusLabel->setText(QString("Statuse: %1 todo / %2 completed") .arg(todoCount) .arg(completedCount)); } //***************************** List::~List() { delete vBox; }
Task.h:
#ifndef TASK_H #define TASK_H #include <QWidget> #include <QString> class QCheckBox; class QPushButton; class QHBoxLayout; class Task : public QWidget { Q_OBJECT public: explicit Task(const QString&, QWidget* parent = nullptr); void setName(const QString&); QString name() const; bool isCompleted() const; ~Task(); public slots: void rename(); signals: void removed(Task*); void statusChanged(Task*); private slots: void checked(bool); private: QCheckBox* checkbox; QPushButton* editButton; QPushButton* removeButton; QHBoxLayout* hBox; }; #endif // TASK_H
Task.cpp:
#include "task.h" #include "list.h" #include <QInputDialog> #include <QWidget> #include <QHBoxLayout> #include <QPushButton> #include <QCheckBox> Task::Task(const QString& name, QWidget* parent) : QWidget (parent) { checkbox = new QCheckBox; editButton = new QPushButton(tr("Edit")); removeButton = new QPushButton(tr("Remove")); hBox = new QHBoxLayout; hBox->addWidget(checkbox); hBox->addStretch(); hBox->addWidget(editButton); hBox->addWidget(removeButton); setLayout(hBox); setName(name); connect(editButton, &QPushButton::clicked, this, &Task::rename); connect(removeButton, &QPushButton::clicked, [this]()->void { &List::removeTask(this); // call the function/slot }); connect(checkbox, &QCheckBox::toggled, this, &Task::checked); }; //************************************* void Task::setName(const QString& name) { checkbox->setText(name); } //******************************************** QString Task::name() const { return checkbox->text(); } //***************************** bool Task::isCompleted() const { return checkbox->isChecked(); } //**************************************** void Task::rename() { bool ok; QString value = QInputDialog::getText(this, tr("Edit task"), tr("Task name"), QLineEdit::Normal, this->name(), &ok); if(ok && !value.isEmpty()) setName(value); } //************************************ void Task::checked(bool checked) { QFont font(checkbox->font()); font.setStrikeOut(checked); checkbox->setFont(font); emit statusChanged(this); } //************************************************** Task::~Task() { delete hBox; }
Why do I get the following error for this part please:
connect(removeButton, &QPushButton::clicked, [this]()->void { &List::removeTask(this); // call the function/slot });
Error: Call to non-static member function without an object argument
From my view, all the requirements are supplied, but still get this error!
-
@tomy
since removeTask() is not static (as the error says) you also need to capture an instance of Listconnect(removeButton, &QPushButton::clicked, [this,list]()->void { list->removeTask(this); // call the function/slot });
-
You're right. Inside the lambda body, it's cpp not Qt stuff.
However, the version above doesn't work either.
I think I need an instance (pointer) of the class List in the header of Task as, say, list, and then inside Task.cpp it must be initialized and after that it must be used the way above.still
connect(removeButton, &QPushButton::clicked, [this,list]()->void { list->removeTask(this); // call the function/slot });
would be incorrect: list doesn't name a variable*
And it's good:
connect(removeButton, &QPushButton::clicked, [this]()->void { list->removeTask(this); // call the function/slot });
-
@tomy said in Using a lambda in a connection:
I think I need an instance (pointer) of the class List
Of course you need - that's what @raven-worx told you. If there is no variable/member named "list" the suggested solution cannot work...