質問

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?

役に立ちましたか?

解決 3

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.)

他のヒント

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.

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

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

Signals & Slots is a different coding style. You can do things with signals that can be useful and neat work arounds to traditional c++. For example you can emit const signals from const functions and have them connect to non const slots (where as in c++ you cannot make non const calls from a const function). I've never liked using mutable objects, so signals provide a clean work around for me.

ライセンス: CC-BY-SA帰属
所属していません StackOverflow
scroll top