C++ 使用发射与调用信号,就好像它是 Qt 中的常规函数​​一样

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/10160476/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-27 13:41:11  来源:igfitidea点击:

Using emit vs calling a signal as if it's a regular function in Qt

c++qt

提问by sashoalm

Let's say I have this signal:

假设我有这个信号:

signals:
    void progressNotification(int progress);

I only recently learned about the emit keyword in Qt. Until now, I used to execute signals by just calling them like a regular function. So instead of:

我最近才了解 Qt 中的 emit 关键字。到现在为止,我曾经通过像普通函数一样调用它们来执行信号。所以而不是:

emit progressNotification(1000 * seconds);

I would write:

我会写:

progressNotification(1000 * seconds);

Calling them like that seemed to work, and all the connected slots would execute, so does using the emit keyword cause a different behaviour, or is it just syntactic sugar?

像这样调用它们似乎有效,并且所有连接的插槽都会执行,所以使用 emit 关键字会导致不同的行为,还是只是语法糖?

采纳答案by Mat

emitis just syntactic sugar. If you look at the pre-processed output of function that emits a signal, you'll see emitis just gone.

emit只是语法糖。如果您查看发出信号的函数的预处理输出,您会发现emit它已经消失了。

The "magic" happens in the generated code for the signal emitting function, which you can look at by inspecting the C++ code generated by moc.

“魔法”发生在信号发射函数的生成代码中,您可以通过检查 moc 生成的 C++ 代码来查看。

For example a foosignal with no parameters generates this member function:

例如,一个foo没有参数的信号生成这个成员函数:

void W::foo()
{
    QMetaObject::activate(this, &staticMetaObject, 0, 0);
}

And the code emit foo();is pre-processed to simply foo();

并且代码emit foo();被预处理为简单foo();

emitis defined in Qt/qobjectdefs.h(in the open-source flavor of the source anyway), like this:

emit定义在Qt/qobjectdefs.h(无论如何都在源代码的开源风格中),如下所示:

#ifndef QT_NO_EMIT
# define emit
#endif

(The define guard is to allow you to use Qt with other frameworks that have colliding names via the no_keywordsQMake config option.)

(定义保护是允许您通过no_keywordsQMake 配置选项将 Qt 与具有冲突名称的其他框架一起使用。)

回答by NameRakes

After 18 months ... I started with comments under @Mat's answer, and was running out of room quickly. Thus the answer.

18 个月后......我开始在@Mat 的回答下发表评论,但很快就没有空间了。于是有了答案。

IMO emitis neither syntactic sugar nor a simple keyword in the sense that

emit从某种意义上说,IMO既不是语法糖,也不是简单的关键字

  1. It generates code (as explained by @Mat above),
  2. It helps the connectmechanism recognize that indeed it is a signal, and
  3. It makes your signal part of a "bigger" system, where signals and responses (slots) can be executed synchronously or asynchronously, or queued, depending on where and how the signal got emitted. This is an extremely useful feature of the signal/slot system.
  1. 它生成代码(如上面@Mat 所解释的),
  2. 它有助于connect机制认识到它确实是一个signal, 并且
  3. 它使您的信号成为“更大”系统的一部分,在该系统中,信号和响应(槽)可以同步或异步执行,或排队,具体取决于信号发出的位置和方式。这是信号/插槽系统的一个非常有用的功能。

The entire signal/slot system is a different idiom than a simple function call. I believe it stems from the observer pattern. There is also a major difference between a signaland a slot: a signal does not haveto be implemented, whereas a slot must be!

整个信号/槽系统与简单的函数调用是不同的习惯用法。我相信它源于观察者模式。asignal和 a之间还有一个主要区别slot不必实现信号,而必须实现槽!

You are walking down the street and see a house on fire (a signal). You dial 911 (connect the fire signal with the 911 response slot). The signal was only emitted, whereas the slot was implementedby the fire department. May be imprecise, but you get the idea. Let's look at the example of OP.

你走在街上,看到一座房子着火了(一个信号)。您拨打 911(将火警信号与 911 响应插槽连接)。信号只是发出,而插槽由消防部门实施的。可能不精确,但你明白了。让我们看一下 OP 的例子。

Some backend object knows how much progress has been made. So it could simply emit progressNotification(...)signal. It is up to the class that displays the actual progress bar, to pick up this signal and execute on it. But how does the view connect to this signal? Welcome to Qt's signal/slot system. One can now conceive of a manager class (typically a widget of sorts), which consists of a view object and a data computation object (both being QObjects), may perform connect (m_myDataEngine, &DataEngine::progressNotification, m_myViewObj, &SimpleView::displayProgress).

一些后端对象知道已经取得了多少进展。所以它可以简单地emit progressNotification(...)发出信号。由显示实际进度条的类来获取此信号并对其执行。但是视图如何连接到这个信号呢?欢迎使用 Qt 的信号/插槽系统。现在可以设想一个管理器类(通常是各种小部件),它由一个视图对象和一个数据计算对象(两者都是QObjects)组成,可以执行connect (m_myDataEngine, &DataEngine::progressNotification, m_myViewObj, &SimpleView::displayProgress).

Let's not get into the design aspects of the manager class, but suffice it to say that this is where signal/slot system shines. I can focus on designing a very clean architecture for my application. Not always, but often times, I find that I merely emit signals but implement slots.

让我们不要进入管理器类的设计方面,但足以说明这是信号/插槽系统的亮点。我可以专注于为我的应用程序设计一个非常干净的架构。并非总是如此,但很多时候,我发现我只是发出信号,但实现了 slot

If it is possible to use/call a signal method without ever emitting it, then it necessarily implies that you never needed that function as a signalin the first place.

如果可以在不发出信号的情况下使用/调用,那么它必然意味着您从一开始就不需要该函数作为信号

回答by Evert

The second option would imply that you always know what the function name and the function parameters are and that the object which are you sending it to is known by that particular function. Those two cases are not always true, so that are the two main things why slots and signals have been made. "under-the-hood" the signal and slot mechanism is just a table with pointers to every function that is connected.

第二个选项意味着您始终知道函数名称和函数参数是什么,并且该特定函数知道您将其发送到的对象。这两种情况并不总是正确的,所以这是产生槽和信号的两个主要因素。“幕后”信号和插槽机制只是一个表,其中包含指向每个连接函数的指针。

Also, look at this pdf which explains very clearly the nature of the signals and slots mechanism: http://www.elpauer.org/stuff/a_deeper_look_at_signals_and_slots.pdf

另外,看看这个 pdf,它非常清楚地解释了信号和插槽机制的性质:http: //www.elpauer.org/stuff/a_deeper_look_at_signals_and_slots.pdf