2

With Qt 4.8 I create a number of input widgets (QSpinBox, QSlider) programmatically. In the end, I would like to have a single method to handle changes of any of these input widgets, ideally by index.

However, these widgets only have a Signal with parameter, e.g. valueChanged(int). This is not compatible with QSignalMapper()'s Slot map().

As it was pointed out in the comments, the connection does work!

    connect(    spinbox,        SIGNAL( valueChanged(int)  ),
                signalMapper,   SLOT(   map()            )
                );

Now I just need to get the value, but this cannot be done via the sender() method anymore, because this now is the SignalMapper.


Original question:

Is there another way besides (re)implementing QSignalMapper with additional parameters or a parameter-less valueChanged() for the widget or using objectName and QObject::sender() in order for the Slot to see which element changed (and get the new value)?

handle
  • 5,859
  • 3
  • 54
  • 82
  • can't you just query the new value in the slot listening to the mapper (you can signal with more parameters than a slot takes) – ratchet freak Jul 02 '14 at 12:55
  • You don't need to repimplement `QSignalMapper`. Just create an instance of `QSignalMapper` and define mappings for it. It supports mapping of various datatypes, so you can define integers, strings, or even anything that casts to `QObject*`. What other information would you expect in the slot? – Googie Jul 02 '14 at 12:56
  • See this: http://stackoverflow.com/questions/24260394/how-works-qsignalmapper for how to correctly use `QSignalMapper`. This is really the best solution for what you need to do. – Googie Jul 02 '14 at 13:06
  • @Googie Yes, I would not mind using QSignalMapper, but my widgets don't have the equivalent to the clicked() method used in the example solution you posted. Or I still don't get it - could you post an example in an answer? – handle Jul 02 '14 at 13:39

2 Answers2

1

You can use QAbstractSpinBox::editingFinished() and QAbstractSlider::sliderReleased() as your signals, they are parameterless.

Unfortunately there is no parameterless version of QAbstractSlider::valueChanged() so if you want a signal emitted continuously as the slider moves, you may need to subclass QSlider and create it. E.g.

class MySlider : public QSlider
{
   ...
   private slots:
      void HandleValueChanged(int) { emit valueChanged(); }
   signals:
      void valueChanged();
};

MySlider::MySlider(...)
{
    connect(this, SIGNAL(valueChanged(int)), this, SLOT(HandleValueChanged(int)));
}

Though I admit, this may not be the most elegant solution.

Matt Phillips
  • 9,465
  • 8
  • 44
  • 75
  • This doesn't solve the main problem here - having the index of the issuer passed to the slot. – Googie Jul 02 '14 at 12:58
  • True, but you can cast QObject::sender() to the right object, and ask it's currentIndex() (it is ugly). – hauron Jul 02 '14 at 12:59
  • @Googie Doesn't it? `QSignalMapper` creates the equivalent of an index, that's what it's for. It just needs a parameterless signal. – Matt Phillips Jul 02 '14 at 13:01
  • @MattPhillips Yes, but if I understand the question correctly, @handle asked if there is any other way than `QObject::sender()` or `QSignalMapper`. Truth is that the `QSignalMapper` is the best fit for this, and that's what I suggested him in the comment under his query. I don't really understand why is he looking for other solution - maybe he uses `QSignalMapper` in a wrong way. – Googie Jul 02 '14 at 13:04
  • @Googie Ok, on a strictly literal reading of OP's question you are right but I gather he/she would be satisfied with finding out that `QSignalMapper` works after all--as you try to show in your comments. So we're on the same wavelength I think. – Matt Phillips Jul 02 '14 at 13:09
  • My assumption (?) was wrong - see @ratchet freak's comment to the question, and my changes to the question. – handle Jul 02 '14 at 13:52
0

If I understand your question and what you have until now correctly, you are missing two parts.

mapper->setMapping(<spinbox>, <id or name or pointer to the spinbox);
connect(mapper, SIGNAL(mapped(<datatype you used in setMapping()>),
this, SLOT(HandleValueChanged(<datatype you used in setMapping()>)));

So the HandleValueChanged() slot will receive an identifier of your sender, then you can directly access the value of the sender with the appropriate getter. The method setMapping() takes either and integer, QString or a pointer to the widget itself as second argument. This is then forwarded via the mapped() signal of the mapper, so you can later identify which widget emitted the signal.

Daniel82
  • 101
  • 7
  • Yes, the data then can be accessed like `int n = qobject_cast(widget)->value();`, similar to a direct connection with using sender(), but this also does not provide an index. However, can somehow be mapped .. – handle Jul 02 '14 at 15:21
  • Sorry, somehow I don't understand your question/comment. What do you mean with "does not provide an index"? What kind of index do you want? Usually you select an index for each widget yourself when calling the setMapping() method for each widget you want to catch changes for. – Daniel82 Jul 02 '14 at 15:26
  • With index I mean what you refer to as id. I would like both, the widgets value, and an id, but QSignalMapper can only do either. But there are lots of ways. Thanks for your input! – handle Jul 02 '14 at 15:56