Qt 5 assign slot with parameters to a QPushButton
Asked Answered
C

1

10

I have a Qt application on C++ and I want to assign a slot to a QPushButton. But I want to pass some arguments because I have more than one QPushButton doing similar thing so I want one function but with a parameter in it but Qt keeps saying me that there is no slot like this. Can someone tell me why and how should I do it?

Thank you in advance

In the .h file I have: (it was private in the beginning but I changed it in searching of the problem)

public slots:
    void handleButton(int row, int col);

Then in the .cpp:

void fieldWindow::handleButton(int row, int col){
    cout << row << " " << col << endl;
}

And again in the same .cpp:

connect(this->buttonsField[i][j], SIGNAL(released()), this, SLOT(handleButton(i,j)));

This is done in two nested loop so i and j are well defined.

And my error is:

QObject::connect: No such slot fieldWindow::handleButton(i,j) in ..\Proj1\fieldwindow.cpp:41
QObject::connect:  (receiver name: 'fieldWindow')

I read something in the internet that I should say handleButton(int, int); but then how should I pass the arguments ?

Cabstand answered 16/1, 2014 at 0:3 Comment(2)
The connect statement does not accept any arguments within a SIGNAL(...) expression. SIGNAL is a macro which encapsulates a function signature in a string to be passed to connect.Rehearsal
So it should be handleButton(int,int)?! But how do I pass the arguments then ?!Cabstand
R
15

Sadly, a Qt signal-slot connection doesn't accept any arguments to be passed to the slot when the signal is called. This only works if the signal itself provides those arguments, but you can't add them in a connect statement.

But you're not the only one who wants to do this, so in Qt there is a class which does almost what you want: QSignalMapper. An instance of this class can be used as a "proxy" for a signal-slot connection: you connect (multiple) buttons to a slot of this class, and connect a signal of this class to your target slot. Then, for each "sender" instance (in your case buttons), you can tell the class which value to add to the called slot. Example:

QPushButton * button1 = ...;
QPushButton * button2 = ...;

QSignalMapper mapper;

connect(button1, SIGNAL(released()), &mapper, SLOT(map()));
mapper.setMapping(button1, 42); // Number to be passed in the slot

connect(button2, SIGNAL(released()), &mapper, SLOT(map()));
mapper.setMapping(button2, 1337); // Number to be passed in the slot

connect(&mapper, SIGNAL(mapped(int)), this, SLOT(handleButton(int)));

Sadly, as you can see this class can only handle a single parameter. For your case, you should choose a different method (I explained the above in case you encounter a similar problem again but with a single int parameter).

The alternative which fits your problem is to rely on sender() within the slot. Remember your mapping in a data structure like

QMap<QObject*,int> rows;
QMap<QObject*,int> cols;

and access those in your slot which takes no argument:

void fieldWindow::handleButton(){
    int row = rows[sender()];
    int col = cols[sender()];
    cout << row << " " << col << endl;
}

Of course, when initializing your UI, you need to put appropriate values in these maps. Or you could search your button in your existing array buttonsField.

Another method exists since Qt5 and C++11: Instead of a slot, you can handle the signals in a lambda function. This would look like this (the signal is named using a new syntax):

connect(this->buttonsField[i][j], &QPushButton::released, [=]{
    handleButton(i, j);
});

If you don't like the lambda syntax, it's also possible to use some helpers from the standard library to compose a functor instead of a lambda, or you can write your own functor class, but personally I find the lambda very readable.

Rehearsal answered 16/1, 2014 at 0:27 Comment(3)
Thank you a lot ! I can reduce to one with simple formula i*count_on_row + j so I'll try the first way and I hope it will work! Thank you a lot with the detailed answer :)Cabstand
I'm glad I could help. I added a third method which is nice if you have Qt5. Please note that in case you only need those values in order to access your array of buttons for getting the button pointer, you can also simply use sender() and you're done.Rehearsal
Ohhh they added lambda! Great! This worked perfectly! Thank you so much! :)Cabstand

© 2022 - 2024 — McMap. All rights reserved.