Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Using Qt signals and slots vs calling a method directly

Lets say I have a main window with a slider and a widget inside that window with a method called setValue(int). I'd like to call this method every time the value of the slider has changed.

Is there any practical difference between the two following ways of achieving it:

1

void MainWindow::on_slider_valueChanged(int value)
{
    ui->widget->setValue(value);
}

2

// somewhere in constructor
connect(ui->slider, SIGNAL(valueChanged(int)), ui->widget, SLOT(setValue(int)));

For me the first approach looks better, because it possibly avoids some overhead related to signals and slots mechanism and also, allows me to process the value before sending it to widget, if there's a need for it.

Are there any scenarios where the second solution is better?

like image 951
jaho Avatar asked Feb 19 '14 23:02

jaho


4 Answers

Both approaches use signal-slot connections. In the first case, the connect call is made by QMetaObject::connectSlotsByName() called from setupUi. In the second case, you explicitly call connect yourself.

Also, the first approach is unnecessary in Qt5 when using C++11. You can modify the value in a lambda:

QObject::connect(ui->slider, &QAbstractSlider::valueChanged,
                 [this](int val){ ui->widget->setValue(val*2); });

To protect from deletion of ui->widget, you should use a QPointer:

class MyWindow : public QMainWindow {
  QPointer<QAbstractSlider> m_widget;
  ...
public:
  MyWindow(QWidget * parent = 0) : QMainWindow(parent) {
    ...
    setupUi(this);
    m_widget = ui->widget;
    QObject::connect(ui->slider, &QAbstractSlider::valueChanged, 
                    [this](int val)
    {
      if (!m_widget.isNull()) m_widget->setValue(val*2); 
    });

The overhead of signal-slot connections is quantified in this answer.

like image 113
Kuba hasn't forgotten Monica Avatar answered Oct 10 '22 14:10

Kuba hasn't forgotten Monica


Signal/slot advantages:

  • multiple slots can be connected to single signal, and you don't bother with allocating and freeing memory for this
  • you can handle multithreading with this

Signal/slot drawbacks:

  • a little slower than direct call
  • significantly slower if the slot is virtual
  • QObject is rather heavy thing, so you usually try to avoid constructing billions of them

More details are available here

like image 29
Kirill Gamazkov Avatar answered Oct 10 '22 14:10

Kirill Gamazkov


The main difference, in your example, of using a signal instead of a direct call, is to allow more than one listener.

If you directly call your widget setValue(), then only that one widget will receive the C++ signal.

If you use a Qt signal, now any other object can connect to receive the event whenever it occurs.

If you do not foresee any other object to ever want to receive the value by signal, I would not bother with such. A direct call is definitively a lot faster (between 3 and 6 CPU instructions instead of dealing with strings to find receivers!), but as Paranaix mentioned, in a GUI it may not be much of an issue (although in this case it could become a problem on older computers if you send all those signals while moving the sliderbar.)

like image 38
Alexis Wilke Avatar answered Oct 10 '22 13:10

Alexis Wilke


I prefer the second method, since it happened that I forgot to delete the "auto-connect-slots" when the UI-element was removed, causing dead code. AFAIK it is the same "behind the scene" (look at the auto-generated qt-files).

When you would like to modify the value I would prefer following method:

connect(ui->slider, SIGNAL(valueChanged(int)), this, SLOT(myOwnSlot(int)));

void MainWindow::myOwnSlot(int value) {
    /** do stuff */
    ui->widget->setValue(value);
}

Greetz

like image 26
Robert Avatar answered Oct 10 '22 13:10

Robert