1

I'm currently working on a game with a friend of mine, and now we are kind of stuck. We need to pass two arguments to a slot. I want to use one slot for two buttons, and one of the buttons will be used for adding, and the other one for subtracting. This will be one of the arguments, either 0 (for subtracting) or 1 (for adding). The other argument will be a kind of ID, because i will have several sets of these two buttons. I've used several other slots in my code, and on these slots I've been using QSignalMapper like this:

Button * button = new Button(argument1, argument2, argument3);

int num = 1;

QSignalMapper * signalMapper = new QSignalMapper(this);

connect(button, SIGNAL(clicked()), signalMapper, SLOT(map)));
signalMapper->setMapping(button, num);
connect(signalMapper, SIGNAL(mapped(int)), this, SLOT(mySlot(int)));

scene->addItem(button);

Is there any way I can pass two arguments to a slot?

sandwood
  • 2,038
  • 20
  • 38
Dromnes
  • 302
  • 2
  • 3
  • 12
  • I am not really familiar with qt, but what about a `pair` ? – 463035818_is_not_an_ai Jun 23 '16 at 19:50
  • How do I use `pair`? – Dromnes Jun 23 '16 at 20:18
  • are slots and signals really restricted to only one parameter? However, see here : http://en.cppreference.com/w/cpp/utility/pair – 463035818_is_not_an_ai Jun 23 '16 at 20:24
  • ***are slots and signals really restricted to only one parameter?*** No they are not limited to just 1 parameter. `QSignalMapper` is however. – drescherjm Jun 23 '16 at 20:43
  • Is Button your own class, derived from QButton? – JvO Jun 23 '16 at 21:17
  • @JvO `Button` is my own class yes, but I've don't made it out of `QButton`. It is a `QRect` object I've styled with `QPixmap`. – Dromnes Jun 23 '16 at 21:21
  • Then why don't you simply pass the two arguments in your own clicked() signal? Forget the SignalMapper and use the sender() trick described below... – JvO Jun 23 '16 at 21:25
  • I don't actually know how I should do it. Because the arguments is not defined yet when I create the object. – Dromnes Jun 23 '16 at 21:27
  • I rewrote my answer so it shows how to send multiple arguments in a signal. But your comment "the argument is not defined" does not make much sense... – JvO Jun 23 '16 at 21:38
  • [This answer](http://stackoverflow.com/a/22411267/1329652) to the duplicate question is what you're looking for. Not only you can pass multiple arguments, you can execute arbitrary code for each connection, given inside of the call to `connect`. It's as concise as it gets. – Kuba hasn't forgotten Monica Jun 23 '16 at 23:34
  • @KubaOber I don't actually see how that answer can help me. – Dromnes Jun 24 '16 at 12:54
  • @Dromnes Doesn't `connect(button1, &QPushButton::clicked, this, [this]{ mySlot(1,2,3,4); });` work for you? You don't need a signal mapper in modern Qt code, it was a workaround for deficiencies of the C++ language prior to C++11. If you want to do something else, you should post code that shows the example without using the signal mapper - just use one slot per button to demonstrate what you intend to do. And then note that whatever you put into the dedicated slot can go into a lambda. And then you're done. – Kuba hasn't forgotten Monica Jun 24 '16 at 14:52

3 Answers3

4

Use the sender() function instead:

void mySlot()
{
    if (sender() == addButton)
        ...
    else
        ...
}

In your case, you can remove the int argument from mySlot and do the following:

 connect(addButton, SIGNAL(clicked()), someObject, SLOT(mySlot()));
 connect(subButton, SIGNAL(clicked()), someObject, SLOT(mySlot()));

Then use the sender function to determine the source.

To directly answer your question, yes, you can define a slot that accepts up to 8 arguments (pre C++11) or any number (C++11 or later). The issue is that they must be connected to a signal with as many or more parameters.

Example, if you have a signal with the signature notify(int, bool, QString) you can connect it to a slot with any of the following signatures:

  • someSlot(int)
  • someSlot(int, bool)
  • someSlot(int, bool, QString)
jonspaceharper
  • 4,207
  • 2
  • 22
  • 42
  • Hrmpf. You beat me to it :) – JvO Jun 23 '16 at 20:44
  • @Jon Harper When I use the `sender()` function the sender is `QSignalMapper(0x324e028)`, so I don't actually understand how i should use it. – Dromnes Jun 23 '16 at 21:03
  • Eliminate `QSignalMapper` entirely and connect the button's `clicked` signal to `mySlot`. Instead of accepting an `int` as an argument, use `sender()` to determine which button is the source. – jonspaceharper Jun 23 '16 at 21:27
  • E.g. `connect(button, SIGNAL(clicked()), someObject, SLOT(mySlot()));` – jonspaceharper Jun 23 '16 at 21:29
  • @Dromnes I've expanded my answer to clarify a bit. – jonspaceharper Jun 23 '16 at 21:35
  • 1
    I've tried out your suggestions and different variants of it for several hours, but it don't seem like I'm able to make it work. I just made two slots to be able to move on with my code. – Dromnes Jun 24 '16 at 12:59
3

QSignalMapper has a single parameter only. But you can use one of the following ways to split buttons into the several sets:

  • start each set ID from a known number, i.e. first set starts from 100, the second set from 200 and so on, and you can easily detect the set dividing a number by 100: 102 stands for the first set and button ID = 2;
  • use mapping with QString where you can use some token to split a set number from a button number, i.e. 1;2 (the first set, button ID = 2) using QString::split().

Example of the slot:

void mySLot (const QString& id)
{
    QStringList tokens = id.split (";");

    if (tokens.count () == 2) {
        int setId    = tokens.at(0).toInt ();
        int buttonId = tokens.at(1).toInt ();

        /* Your code goes here */
    }
}
2

[completely revised answer]

So, we have an Button object with multiple arguments that need to be passed on in a slot.

class Button
{
   Q_OBJECT
 public:
   int m_arg1, m_arg2, m_arg3;

   Button(int arg1, int arg2, int arg3)
   {
      m_arg1 = arg1;
      m_arg2 = arg2;
      m_arg3 = arg3;
   };

   /// some function that emits a click signal with 2 of my arguments
   void doSomething()
   {
       emit clicked (m_arg2, m_arg3);
   }

 signals:
   void clicked(int, int);
};

Then, later on:

Button *button = new Button(val1, val2, val3);
connect(button, SIGNAL(clicked(int, int)), this, SLOT(mySlot(int, int)));

MyReceiver::mySlot(int a1, int a2)
{
  // see who called me, then use arguments
  if (addButton == sender())
  {
     x = a1 + a2;
  }
  else if (subButton == sender())
  {
     x= a1 - a2;
  }
}
JvO
  • 3,036
  • 2
  • 17
  • 32
  • When I do as you suggested my `sender()` or `who` is `QSignalMapper(0x323e298)`, so I don't understand how I should use it. – Dromnes Jun 23 '16 at 21:08
  • Sorry; in this case you need to connect the sigals directly and leave the signalMapper out. Oh wait, I got an idea... – JvO Jun 23 '16 at 21:16
  • I seems like I'm doing somthing wrong all the time. I've work on this problem for several hours, but nothing works, so I simply just made two slots to move on with my code. – Dromnes Jun 24 '16 at 13:04
  • Would this example work? I doubt because according to the [docs](http://doc.qt.io/qt-5/qabstractbutton.html#clicked) `clicked()` accepts only `bool` as argument. I'd like more information regarding this. Thank you. – Deniz Oct 04 '16 at 06:30
  • @deniz Yes, because I defined a clicked(it,int) signal in the Button class. – JvO Oct 04 '16 at 09:07
  • @JvO ah it seems I wasn't paying attention. Looks like I mixed up `Button::clicked()` with `QPushButton::clicked()`. I can see it now, thank you for this example. – Deniz Oct 04 '16 at 10:29