drkalmenius drkalmenius - 1 year ago 141
C++ Question

Passing arguments to a slot in qt5 c++

I'm creating a ToDo list app in c++ qt. When a plus button is pressed, it adds a QHBoxLayout containing a QLabel and a QToolButton to a vertical layout inside my gui, so I get new boxes with the 'ToDos' inside them, and buttons to remove them next to them. I have set up the various widgets inside my slot which is called when the add button is clicked. However, I need to pass them as arguments to the slot which is called when a remove button is pressed. I have researched already, and all I have found is QSignalMapper. However, I cannot find any cases close enough to mine to replicate, and I have read it only works with certain arguments, and not the three I need (QHBoxLayout, QLineEdit and QToolButton).
Some of the code for the slot which is called when the 'add' button is pressed is:

//Creates a read only LineEdit which the user will add
QLineEdit *toDoBox = new QLineEdit(this);

//Creates a new X button for removal of ToDo's
QToolButton *removeButton = new QToolButton;

//Adds a horizontal layout with the ToDo and the remove button in it, to keep them together
QHBoxLayout *toDoLayout = new QHBoxLayout;

//Removes a ToDo when the remove button is clicked
connect(removeButton, SIGNAL(clicked()), this, SLOT(on_removeButton_clicked()));

My code is hosted on GitHub if you want to see the whole project:

Thanks for bearing with me- I struggle explaining things that are so clear in my head!

Answer Source

If I understand well your problem, you want to get the allocated objects which represent a todo in order to free them and to update your View.

You could achieve this by simply wrapping your QLineEdit, QToolButton and QHBoxLayout objects into a class, and use a container (a vector for instance) in your ToDoList class. That way, you push_back your "todo object" each time you press the on_toolButton_clicked method.

Then, you simply have to use a signal with an index triggering an on_delete_todo slot which deletes a "todo object" from your vector and update the view.

Also, take a look at this Qt Model-View Programming

Here is a sample (tested and working under QT5):

Your Todo Widget

#ifndef TODOVIEW_H
#define TODOVIEW_H

#include <QString>

class QLineEdit;
class QToolButton;
class QHBoxLayout;

#include <QWidget>

class TodoView : public QWidget

    QLineEdit*      frame;
    QToolButton*    removeButton;
    QHBoxLayout*    toDoLayout;
    int             index;

    TodoView(const QString& what, int index, QWidget* parent);

    inline void setIndex(int i) { index = i; }
    inline int getIndex(){ return index; }

private slots:
    void emitIndex();

    void selectedIndex(int);


#endif // TODOVIEW_H

#include "todoview.h"

#include <QLineEdit>
#include <QToolButton>
#include <QHBoxLayout>

TodoView::TodoView(const QString& what, int index, QWidget* parent) : QWidget(parent), index(index)
    frame = new QLineEdit(this);

    removeButton = new QToolButton(this);

    toDoLayout = new QHBoxLayout(this);

    connect(removeButton, SIGNAL(clicked()), this, SLOT(emitIndex()));

TodoView::~TodoView() {}

void TodoView::emitIndex()
    emit selectedIndex(getIndex());

Your MainWindow


#include <QMainWindow>

#include <vector>

class TodoView;
class QVBoxLayout;

namespace Ui {
    class MainWindow;

class MainWindow : public QMainWindow

    explicit MainWindow(QWidget *parent = 0);

private slots:
    void addTodo();
    void delTodo(int);

    Ui::MainWindow*         ui;

    QVBoxLayout*            vBoxLayout;

    std::vector<TodoView*>  todoView;
    int                     max = -1;

#endif // MAINWINDOW_H

#include "mainwindow.h"
#include "ui_mainwindow.h"

#include "todoview.h"

#include <QVBoxLayout>
#include <QAction>

MainWindow::MainWindow(QWidget *parent) :
ui(new Ui::MainWindow)

    vBoxLayout = new QVBoxLayout(centralWidget());

    QAction* add = new QAction(ui->mainToolBar);

    connect(add, SIGNAL(triggered()), this, SLOT(addTodo()));

    delete ui;

void MainWindow::addTodo()
    if(max > 9)
        // Error msg.
        TodoView* tdV = new TodoView("Yolo", max, centralWidget());
        connect(tdV, SIGNAL(selectedIndex(int)), this, SLOT(delTodo(int)));


void MainWindow::delTodo(int i)
    // check if i < todoView.size().
    delete todoView.at(i);
    // update vector indexes !!!

I have edited this piece of code rapidly, I may have made several mistakes, but you have an idea of at least one solution.

It is also possible to use a fixed size for the vector (better solution). Setting the TodoView deleted objects to nullptr in the vector and search for nullptr when you want to add new Todo view components:

In the MainWindow constructor

for(std::size_t i = 0; i < 10; ++i)
    todoView[i] = nullptr;

In the addTodo Slot

// Do not use push back.
// retrieve the max index.
// if < 10
for(std::size_t i = 0; i < todoView.size(); ++i)
    if(todoView[i] == nullptr)
        // allocate TodoView and affect it to the i° element

In the delTodo slot

delete todoView[i];
todoView[i] = nullptr;

Using a vector of pair is also possible (a pair of int TodoView).

Recommended from our users: Dynamic Network Monitoring from WhatsUp Gold from IPSwitch. Free Download