How does QSignalMapper work?
Asked Answered
U

2

11

After my post here : Associate signal and slot to a qcheckbox create dynamically I need to associate :

• The signal clicked() when I click on a qCheckBox to my function cliqueCheckBox(QTableWidget *monTab, int ligne, QCheckBox *pCheckBox)

To do so, I have to use QSignalMapper, after two hours of trying to understand how it works, I can't have a good result, here's the code I make, this is obviously wrong :

 QSignalMapper *m_sigmapper = new QSignalMapper(this);
 QObject::connect(pCheckBox, SIGNAL(mapped(QTableWidget*,int, QCheckBox*)), pCheckBox, SIGNAL(clicked()));
 QObject::connect(this, SIGNAL(clicked()), this, SLOT(cliqueCheckBox(QTableWidget *monTab, int ligne, QCheckBox *pCheckBox)));

 m_sigmapper->setMapping(pCheckBox, (monTab,ligne, pCheckBox));
 QObject::connect(m_sigmapper, SIGNAL(clicked()),this, SLOT(cliqueCheckBox(QTableWidget *monTab, int ligne, QCheckBox *pCheckBox)));

Can you explain to me, how QSignalMapper works ? I don't really understand what to associate with :(

Unfledged answered 17/6, 2014 at 9:37 Comment(9)
why do you have to use QSignalMapper? any particular reason? this can be done easily with direct connectionSofer
Well, in the other post, they explain to me that a signal can't be connect to a slot with more parameter, and the signal clicked() have no parameters. Also I need those 3 parameters.Unfledged
true, slot can have equal or less number of parameters than corresponding signal. but you can write a slot which takes no parameter, then call the actual slot/method from this with required parameter.Sofer
Yes but how can I pass him the 3 parameters : QTableWidget *monTab, int ligne, QCheckBox *pCheckBox ? If you read the other post you will I have hundred of qCheckBox, so I can't use pointers.Unfledged
@EvansBelloeil For understanding how QSignalMapper works, here is a good example for you to start with.Cathedral
@Cathedral I already read this, but thanks, maybe I'm stupid, but it doesn't help me so much.Unfledged
@EvansBelloeil I think you need QSignalMapper because you have many widgets which emit a signal and you want to know in the destination slot which one has emitted the signal.Stethoscope
@Stethoscope Yes I think too, but I don't really understand how to call the connect function, what is the goal of setMapping, ...Unfledged
@EvansBelloeil That's the greatest example I've ever found and it explains QSignalMapper step by step in details. You just need to ruminate it and it takes time. I think you are just a little bit too urgent on solving this problem; it has nothing to do with being stupid or not.Cathedral
S
14

QSignalMapper class collects a set of parameterless signals, and re-emits them with integer, string or widget parameters corresponding to the object that sent the signal. So you can have one like:

QSignalMapper * mapper = new QSignalMapper(this);
QObject::connect(mapper,SIGNAL(mapped(QWidget *)),this,SLOT(mySlot(QWidget *)));

For each of your buttons you can connect the clicked() signal to the map() slot of QSignalMapper and add a mapping using setMapping so that when clicked() is signaled from a button, the signal mapped(QWidget *) is emitted:

QPushButton * but = new QPushButton(this);

QObject::connect(but, SIGNAL(clicked()),mapper,SLOT(map()));
mapper->setMapping(but, but);

This way whenever you click a button, the mapped(QWidget *) signal of the mapper is emitted containing the widget as a parameter.

Stethoscope answered 17/6, 2014 at 10:16 Comment(6)
Thank you ! It works, but how can i put 3 parameters ? Is this possible ? Because it seems I only can put 1 because of mapped(QWidget *)Unfledged
It is not possible to have more than one parameter. You can have the other widget as class members and access them in the slot.Stethoscope
What do you mean class member ? If I can't pass it as a parameter how can I find ?Unfledged
I mean you can put pointers to your widgets in your class .h file as private. Then you can access them.Stethoscope
No. Global variables should not be used in object oriented programming. You can simply have access to the pointer of your widgets in your class.Stethoscope
Let us continue this discussion in chat.Unfledged
G
14

First I will explain you how QSignalMapper works. Then I will explain you why you don't need it.

How QSignalMapper works:

Create s QSignalMapper. Lets assume that you want to assign an integer value to each checkbox, so every time you click on any checkbox, you will get a signal with the integer value assigned to it.

Connect the mapper signal to your SLOT, that you will implement:

connect(mapper, SIGNAL(mapped(int)), this, SLOT(yourSlot(int)));

Now you can write slot, that will take integer argument. The argument will be different for each checkbox you have.

While you create checkboxes, for each checkbox you need to do following:

mapper->setMapping(checkBox, integerValueForThisCheckbox);
connect(checkBox, SIGNAL(clicked()), mapper, SLOT(map()));

From now on, every time you click on a checkbox, it will emit clicked() signal to the QSignalMapper, which will then map it to the assigned integer value and will emit mapped() signal. You connected to that mapped() signal, so yourSlot(int) will be called with the proper integer value.

Instead of integers, you can assign QString, QWidget* or QObject* (see Qt documentation).

This is how QSignalMapper work.

You don't need it:

  • The QTableWidget *monTab is the single object, it doesn't change. Keep it as a class member field and use it from your slot function.
  • The QCheckBox *pCheckBox - you can get it by casting sender() to QCheckBox*.

Like this:

void supervision::yourSlot()
{
    QCheckBox* pCheckBox = qobject_cast<QCheckBox*>(sender());
    if (!pCheckBox) // this is just a safety check
        return;
}

The sender() function is from QObject, which you do inherit from, so you have access to it.

  • The int linge (it's a line number, right?) - when you create checkboxes, you can store pointers to that checkboxes in QList class field and use it from your slot function find out which line is it, like this:

In class declaration:

private:
    QList<QCheckBox*> checkboxes;

When creating checkboxes:

QCheckBox* cb = new QCheckBox();
checkboxes << cb;

In your slot function:

void supervision::yourSlot()
{
    QCheckBox* pCheckBox = qobject_cast<QCheckBox*>(sender());
    if (!pCheckBox) // this is just a safety check
        return;

    int linge = checkboxes.indexOf(pCheckBox);
}

If you want, you can skip that QList and use QSignalMapper and assign lines to checkboxes using mapper. That's just a matter of what you prefer.

Gollin answered 17/6, 2014 at 10:7 Comment(1)
Thanks for your answer that is very good and very complete. My problem is that there's several QTableWidget, so if I don't use QSignalMapper, my way to access to this QTableWidget is to use parent() on the QCheckBox I think. It seems like i'm force to use lots of tricks, and it may cause problem, because my code has to be flexible. So I will try with QSignalMapper at first. Could you provides me more detail so about it ? (I'm sorry this is very hard for me to understand )Unfledged
S
14

QSignalMapper class collects a set of parameterless signals, and re-emits them with integer, string or widget parameters corresponding to the object that sent the signal. So you can have one like:

QSignalMapper * mapper = new QSignalMapper(this);
QObject::connect(mapper,SIGNAL(mapped(QWidget *)),this,SLOT(mySlot(QWidget *)));

For each of your buttons you can connect the clicked() signal to the map() slot of QSignalMapper and add a mapping using setMapping so that when clicked() is signaled from a button, the signal mapped(QWidget *) is emitted:

QPushButton * but = new QPushButton(this);

QObject::connect(but, SIGNAL(clicked()),mapper,SLOT(map()));
mapper->setMapping(but, but);

This way whenever you click a button, the mapped(QWidget *) signal of the mapper is emitted containing the widget as a parameter.

Stethoscope answered 17/6, 2014 at 10:16 Comment(6)
Thank you ! It works, but how can i put 3 parameters ? Is this possible ? Because it seems I only can put 1 because of mapped(QWidget *)Unfledged
It is not possible to have more than one parameter. You can have the other widget as class members and access them in the slot.Stethoscope
What do you mean class member ? If I can't pass it as a parameter how can I find ?Unfledged
I mean you can put pointers to your widgets in your class .h file as private. Then you can access them.Stethoscope
No. Global variables should not be used in object oriented programming. You can simply have access to the pointer of your widgets in your class.Stethoscope
Let us continue this discussion in chat.Unfledged

© 2022 - 2024 — McMap. All rights reserved.