Important: Please read the Qt Code of Conduct -

QSignalMapper and QSpinBox with 2 parameters

  • Hi,

    I have a QSpinBox and I would like to connect it to a slot with 2 parameters when clicking on the arrows. The signal used is valueChanged() from the spinbox The first parameter for the slot would be the spinbox value (imageindex in the slot) and the second one is also an integer (number in the slot).
    I wrote this:

    QSignalMapper*  signalMapper = new QSignalMapper(this);
    connect(ui.spinBox_Image_Output, static_cast<void(QSpinBox::*)(int)>(&QSpinBox::valueChanged), signalMapper, static_cast<void(QSignalMapper::*)()>(&QSignalMapper::map));
    signalMapper->setMapping(ui.spinBox_Image_Output, number);
    connect(signalMapper, static_cast<void(QSignalMapper::*)(int)>(&QSignalMapper::mapped), this, &Gen::setImageIconOutput);

    The declaration for the slot is:

    void setImageIconOutput(const int number, const int imageindex);

    There is a trouble when compiling because number of parameters in signal and slot doesn't match. How should I write it ?

    Many thanks

  • Moderators

    @mulfycrowh said in QSignalMapper and QSpinBox with 2 parameters:

    There is a trouble when compiling because number of parameters in signal and slot doesn't match. How should I write it ?

    the only way to achieve this is to connect the signal-mapper to a slot and in this slot you emit a signal with the 2 parameters.

  • Hi just want to add, you could skip sending the imageindex (i.e. the value from the spinbox) thus making your setImageIconOutput() slot requiring only 1 parameter (signalmapper = happy).

    Then to retrieve the spinbox value in setImageIconOutput(), you could just get it from the spinbox control again.

  • I tried:

    connect(ui.spinBox_Image_Output, static_cast<void(QSpinBox::*)(int)>(&QSpinBox::valueChanged), [&](int imageindex) {setImageIconOutput(number, imageindex);});

    but I don't get the correct first parameter at run time. I mean number in the slot.

  • @mulfycrowh replace [&] with [this,number]

  • Don't want to be a pessimist here, but since the lambda captures the number variable, later when the signal fires and the lambda is called, changes to that number variable isn't visible.

    Perhaps, try storing the numbers in say a QMap<int,int> where the imageindex is the key.

  • @hskoglund You fell in my same mistake, see here: (this treats pointers but this case is identical in principal)

  • @VRonin Wow that was a thorough discussion!
    The lambda's capturing stuff can be tricky, for example. I see in your last post:

    QObject::connect(mainTimer,&QTimer::timeout,[&](){qDebug() << *myString;});
    QObject::connect(mainTimer,&QTimer::timeout,[=](){qDebug() << *myString;});

    Both should work fine (with some luck) because the lambda is capturing the pointer, not the string data itself.
    But in this example with number it's an int, so it's captured fully by [number]. But [&] should've worked, maybe number is recreated as a new instance before the signal is fired?

  • @hskoglund QObject::connect(mainTimer,&QTimer::timeout,[&](){qDebug() << *myString;}); crashes because myString went out of scope so the OS should get angry if I try and read unassigned memory.
    Here I think it's the same, number probably either changes value or goes out of scope so passing it by value to the lambda before changing it should work. @mulfycrowh will tell us.

  • @VRonin Thank you VRonin. It runs perfectly !

  • I made a lot of tests and there is sometimes a trouble about the parameter number passed to the slot setImageIconOutput. It sometimes equals to 0 and that induces an exception.

    In fact I have 2 QSpinBox. The first one gives the index of items and each item has several images. The second one lets you change the index of the image and display it.

    So I have a first connection for the first spinbox:

    connect(ui.spinBox1, static_cast<void(QSpinBox::*)(int)>(&QSpinBox::valueChanged), this, &Gen::updateOutput);

    updateOutput is as following:

    void Gen::updateOutput(int number)
    	setImageIconOutput(number, 1);
    	if (!alreadyConnected) {
    		alreadyConnected = true;
    		connect(ui.spinBox2, static_cast<void(QSpinBox::*)(int)>(&QSpinBox::valueChanged), [this, number](int imageindex) {setImageIconOutput(number, imageindex); });

    setImageIconOutput is as following:

    void Gen::setImageIconOutput(const int number, int imageindex)
    	QPixmap pic;
    	QString suffix;
    	QString msg;
    	suffix = m_tools->ordinalSuffix(imageindex+1);
    	msg = msg.append(suffix);
    	msg = msg.append(msg_imageFileInCommandFile);
    	pic.loadFromData(m_outputImage[number][imageindex], "PNG");

    The exception occurs for example when I choose the 3rd item (25 pictures) and chose the last picture (clicking on the down arrow of spinbox2).
    With debugger on VS2015, I see that parameters passed to setImageIconOutput are 0 and 25 instead of 2 and 25: number is false. The exception comes because the first item only has 22 pictures and is obviously on line:

    pic.loadFromData(m_outputImage[number][imageindex], "PNG");

    If you have any idea ...

  • Hi, if you never set alreadyConnected to true, for example by commenting it out:
    // alreadyConnected = true;
    Still get the bug?

  • Yes I still have the bug. I started without using alreadyConnected.
    Please replace ui.spinBox_Image_Output with ui.spinBox2 in setImageIconOutput

  • Hmm maybe you got bitten by the duplicate/multiple connections for same signal/slot syndrome, you could try doing a disconnect just before the connect with lambda flavor:

        setImageIconOutput(number, 1);
        disconnect(ui.spinBox2, static_cast<void(QSpinBox::*)(int)>(&QSpinBox::valueChanged),0,0);
        connect(ui.spinBox2, static_cast<void(QSpinBox::*)(int)>(&QSpinBox::valueChanged), [this, number](int imageindex) {setImageIconOutput(number, imageindex); });

  • @hskoglund Thank you very much. It's OK !

Log in to reply