tags:

views:

1041

answers:

2

I'm trying to get to grips with Qt's signal and slots mechanism. I have an app with a QPushButton and a QSpinBox. When I click the button I want the spinbox to change to 20. What signal and slot do I need to set up?

The code below shows the app, the connect function is the one I am having trouble with. As I understand it the setValue(int) slot of QSpinBox will not work here because the clicked() signal of QPushButton has a different signature, and anyway how would I pass the value 20 to the spinbox? Do I need to write some sort of auxiliary function to act as a slot which calls spinbox->setValue(20)? If so, what form would that take?

int main(int argc, char *argv[])
{
    QApplication app(argc, argv);

    QWidget *window = new QWidget;
    QSpinBox *spinbox = new QSpinBox;
    QPushButton *button = new QPushButton("Set to 20");

    spinbox->setRange(0, 100);

    // What should I put below?
    QObject::connect(button, SIGNAL(clicked()), spinbox, SLOT(???????));

    QLayout *layout = new QHBoxLayout;
    layout->addWidget(spinbox);
    layout->addWidget(button);
    window->setLayout(layout);

    window->show();

    return app.exec();

}
+1  A: 

I think you are looking at a custom SLOT here. A QPushButton::clicked signal will give a boolean (true|false) event. If you catch it using QSpinBox::setValue you won't go very far. The QSpinBox::setValue expects an int and converts the input boolean to 0 or 1 as the case maybe and your spinbox increments by only 1 unit. If you were to write a custom SLOT you can actually set the exact slider value with far more control.

dirkgently
It looks like I need to use Qt Designer to define custom slots...was hoping there was a simpler way in raw code. What about if I subclass QSpinBox and define a new slot that does setValue(20)? Is that the best practice?
20th Century Boy
A wrapper(subclassing/composition) surely works.
dirkgently
+3  A: 

You can either do:

class AuxSignals : public QObject
{
    Q_OBJECT
    ...
    signals:
        void valueChanged(int);
    public slots:
        void buttonClicked() { emit valueChanged(20); }
};

...

// On main.cpp
AuxSignals *auxSignals = new AuxSignals;

QObject::connect(button, SIGNAL(clicked()), auxSignal, SLOT(buttonClicked));
QObject::connect(auxSignals, SIGNAL(valueChanged(int)), spinbox, SLOT(setValue(int)));

or

class AuxSignals : public QObject
{
    Q_OBJECT
    ...
    QSpinBox *m_spinBox;
    public:
        AuxSignals(QSpinBox *spinBox) : m_spinBox(spinBox) {}
    public slots:
        void buttonClicked() { m_spinBox->setValue(20); }
};

...

// On main.cpp
AuxSignals *auxSignals = new AuxSignals(spinBox);

QObject::connect(button, SIGNAL(clicked()), auxSignals, SLOT(buttonClicked()));

I prefer the first option because it doesn't require the AuxSignals class to have a pointer to a specific QWidget.

Gastón
Perfect! I actually prefer the 2nd version as it only uses one connect. Small correction - it should be m_spinBox->setValue(20). Thanks again.
20th Century Boy
Your welcome. I fixed the m_spinBox->setValue(20); instruction.
Gastón