Important: Please read the Qt Code of Conduct - https://forum.qt.io/topic/113070/qt-code-of-conduct

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!


  • Moderators

    @tomy
    since removeTask() is not static (as the error says) you also need to capture an instance of List

    connect(removeButton, &QPushButton::clicked, [this,list]()->void {
                   list->removeTask(this); // call the function/slot
                });
    


  • @raven-worx

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

  • Lifetime Qt Champion

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



  • This post is deleted!

Log in to reply