使用Qt信号和插槽直接调用方法

jah*_*aho 11 c++ user-interface qt class-design signals-slots

假设我有一个带有滑块的主窗口和一个窗口内的窗口小部件,其方法称为setValue(int).每次滑块的值发生变化时,我都想调用此方法.

以下两种实现方式之间是否存在实际差异:

1

void MainWindow::on_slider_valueChanged(int value)
{
    ui->widget->setValue(value);
}
Run Code Online (Sandbox Code Playgroud)

2

// somewhere in constructor
connect(ui->slider, SIGNAL(valueChanged(int)), ui->widget, SLOT(setValue(int)));
Run Code Online (Sandbox Code Playgroud)

对我来说,第一种方法看起来更好,因为它可能避免与信号和插槽机制相关的一些开销,并且,如果需要它,允许我value在发送之前处理widget它.

是否存在第二种解决方案更好的情况?

Rei*_*ica 9

两种方法都使用信号槽连接.在第一种情况下,通过connect调用来进行QMetaObject::connectSlotsByName()调用setupUi.在第二种情况下,你明确地称connect自己为.

此外,在使用C++ 11时,Qt5中不需要第一种方法.您可以修改lambda中的值:

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

为了防止删除ui->widget,您应该使用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); 
    });
Run Code Online (Sandbox Code Playgroud)

在这个答案中量化了信号槽连接的开销.


Kir*_*kov 7

信号/槽优势:

  • 多个插槽可以连接到单个信号,您不必为此分配和释放内存
  • 你可以用这个处理多线程

信号/插槽缺点:

  • 比直接调用慢一点
  • 如果插槽是虚拟的,速度会明显变慢
  • QObject 是相当沉重的东西,所以你通常会尽量避免构建数十亿个

在此处获得更多详细信息

  • + 用于提及多线程。Slot 可能在与信号不同的线程中被调用,这是这种机制的巨大(甚至可能是最好的)优势。 (2认同)

Ale*_*lke 4

在您的示例中,使用信号而不是直接调用的主要区别是允许多个侦听器。

如果你直接调用你的 widget setValue(),那么只有那个 widget 会收到 C++ 信号。

如果您使用 Qt 信号,现在任何其他对象都可以连接以在事件发生时接收该事件。

如果您没有预见到任何其他对象想要通过信号接收值,我不会为此烦恼。直接调用肯定要快得多(3 到 6 个 CPU 指令,而不是处理字符串来查找接收者!),但正如 Paranaix 提到的,在 GUI 中这可能不是什么大问题(尽管在这种情况下它可能会变成如果您在移动滑块时发送所有这些信号,则在旧计算机上会出现问题。)

  • 没有直接调用。两种情况都使用信号槽连接。 (3认同)
  • 您没有提到处理多线程的机制的巨大优势,所以我的-1。分为GUI线程和工作线程是信号&amp;槽的主要用途之一。 (3认同)