2

So, this works:

.h

public slots:
void addMenu(QString passedName);

signals:
void clicked(const QString &text);

.cpp

signalMapper = new QSignalMapper(this);
signalMapper->setMapping(button, QString("passed_value"));
connect(button, SIGNAL(clicked()), signalMapper, SLOT(map()));
connect(signalMapper, SIGNAL(mapped(QString)), this, SLOT(addMenu(QString)));

Now, I am trying to pass a QMap < QString, QString > through to addMenu instead of just a QString, but I get the error: no matching function for call to 'QSignalMapper::setMapping'. Do I need to create a typeDef or something?

.h

public slots:
void addMenu(QMap < QString, QString > map);

signals:
void clicked(const QMap < QString, QString > &map);

.cpp

//map is defined above

signalMapper = new QSignalMapper(this);
signalMapper->setMapping(button, map);
connect(button, SIGNAL(clicked()), signalMapper, SLOT(map()));
connect(signalMapper, SIGNAL(mapped(QObject*)), this, SLOT(addMenu(QMap < QString, QString >)));

EDIT: I also tried adding a typeDef, but still getting same error.

.h

public:
typedef QMap < QString, QString > passedMapType;

public slots:
void addMenu(passedMapType map);

signals:
void clicked(passedMapType map);

.cpp

passedMapType passedMap;
passedMap.insert(QString("key"), QString("value"));

signalMapper = new QSignalMapper(this);
signalMapper->setMapping(button, passedMap);
connect(button, SIGNAL(clicked()), signalMapper, SLOT(map()));
connect(signalMapper, SIGNAL(mapped(QObject*)), this, SLOT(addMenu(passedMapType));

....

addMenu(passedMapType passedMap) {

}
demonplus
  • 5,613
  • 12
  • 49
  • 68

5 Answers5

3

Use typedefs. My feeling is that the comma between the two QString template parameters is a problem in macro expansion.

Cătălin Pitiș
  • 14,123
  • 2
  • 39
  • 62
3

"Now, I am trying to pass a QMap < QString, QString > through to addMenu instead of just a QString, but I get the error: no matching function for call to 'QSignalMapper::setMapping'."

That's not a general signal/slot or macro expansion problem, but a limitation of QSignalMapper. You can't pass a QMap to setMapping, only int, QString, QWidget* and QObject*. See the QSignalMapper documentation.

connect(signalMapper, SIGNAL(mapped(QObject*)), this, SLOT(addMenu(passedMapType));

That wouldn't work either, because the signatures are incompatible: QObject* vs. QMap.

What I would do: Hold a QMap<QObject*,PassedMapType> in the owner of the buttons, create a slot slotClicked(QObject*) there, connected to the clicked() signals of the buttons, and then look up the PassedMapType object from the map, using the passed QObject*. Edit: added some pseudo code to illustrate it:

QMap<QWidget*, QMap<QString, QString> > map; //member of the class

//when creating the buttons:

for each button b:
    signalMapper->setMapping( b, b );
    map.insert( b, someMapForThisButton );
connect( signalMapper, SIGNAL(mapped(QWidget*)), this, SLOT(addMenuForButton(QWidget*)) );

//the slot:
void addMenuForButton(QWidget* w) {
     const QMap<QString, QString> m = map.value( w );
     create menu...
}
Frank Osterfeld
  • 24,815
  • 5
  • 58
  • 70
  • I will give this a shot; This seems like it should be an easier process. –  Nov 19 '10 at 21:45
  • This doesn't seem as straightforward as it should, have you seen any examples for this? –  Nov 19 '10 at 23:43
1

As a nice work around you can use QObject. QObject has an embedded QMap inside. Here is how it goes:

void sender() {
  ...
  ...
  QObject *data = new QObject(0);
  data->setProperty("Name","xxxx");
  data->setProperty("Address","yyyy");

  //You can also send QImage
  QImage image;
  ...
  data->setProperty("Image",image);

  emit dataReady(data);
 }

signals:
  void dataReady(QObject*);

public slots:
  void receiver(QObject *data) {
    QString Name = data->property("Name").toString();
    QString Address = data->property("Address").toString();
    QImage image = data->property("Image").value<QImage>();
    data->deleteLater();
  }
Omid Sakhi
  • 140
  • 1
  • 5
  • Great idea, I like this approach! – sidewinderguy Jun 08 '17 at 21:48
  • One concern I have is: if there are multiple slots that the 'dataReady' signal is connected to, then won't each of them do a 'data->deleteLater()'? And if so, would that cause a double-delete issue? – sidewinderguy Jun 08 '17 at 21:49
  • According to the docs on deleteLater(): "Note: It is safe to call this function more than once; when the first deferred deletion event is delivered, any pending events for the object are removed from the event queue." I guess that answers my question. I guess as long as all the slots get called from the event loop before it hits the deleteLater() then it's fine, which I think is the case? – sidewinderguy Jun 08 '17 at 21:59
0

This is a pure guess, but you may need to use pointer types instead? I never had very much luck passing by reference with &.

public slots:
void addMenu(QMap<QString, QString> *map);

signals:
void clicked(QMap<QString, QString> *map);
jocull
  • 20,008
  • 22
  • 105
  • 149
  • Qt containers should be passed by const reference, not by pointer. Especially with signal and slots, one runs into all kinds of ownership problems (think queued connections - who deletes the map then?) when using pointers. – Frank Osterfeld Nov 19 '10 at 21:16
0

The signal and slot must have the same argument types (it's a function call, of sorts), so this line is wrong:

connect(signalMapper, SIGNAL(mapped(QObject*)), this, SLOT(addMenu(passedMapType));

You might need to rethink your logic a bit to make that work.

Macke
  • 24,812
  • 7
  • 82
  • 118