题
这个问题已经要求在这一论坛,但我不理解这个概念。
我读周围似乎信号,并插槽是实施使用功能的指针。电子信号是一个很大的功能,内部电话都连接隙(功能的指针).这是正确的?和什么作用所产生的交通部文件在整个故事?我不明白的信号如何能知道槽,呼叫我.e其隙都连接到这一信号。
感谢您的时间
解决方案
Qt以类似解释语言的方式实现这些东西。即它构造符号表,将信号名称映射到函数指针,维护它们并在需要时按函数名称查找函数指针。
每次发出信号,即写
emit something();
你实际上调用 something()
函数,它由元对象编译器自动生成并放入 * .moc
文件中。在此函数中,此时检查此信号连接到哪些插槽,并通过符号表(以上述方式)顺序调用适当的插槽功能(在您自己的源中实现)。与其他特定于Qt的关键字一样, emit
在生成 *。moc
后被C ++预处理器丢弃。实际上,在其中一个Qt标题中( qobjectdefs.h ),存在这样的界限:
#define slots
#define signals protected
#define emit
连接函数( connect
)只修改 * .moc
文件中维护的符号表,以及传递给它的参数(使用 SIGNAL()代码>和`SLOT宏)也被预处理以匹配表。
这是一般的想法。在他或她的另一个答案中,ジョージ 为我们提供链接到trolltech邮件列表并另一个问题。
其他提示
我觉得我应该加入以下。
那里是 另一个关联的问题 -有 一个很好的文章 这可以被认为是一个相当详细的扩展到它的 答案; 这里是这样的文章了, 与改进的(虽然仍然不完美的)代码的语法突出强调。
这是我的简短复述的,那可以容易出错)
基本上,当我们插入 Q_OBJECT
宏在我们的类定义,预处理器的扩大它对一个静态的 QMetaObject
实例宣言》,将共享所有的实例,同一类:
class ClassName : public QObject // our class definition
{
static const QMetaObject staticMetaObject; // <--= Q_OBJECT results to this
// ... signal and slots definitions, other stuff ...
}
这个实例中,反过来,在初始化将储存 签名 ("methodname(argtype1,argtype2)"
)的信号,并插槽,将允许执行 indexOfMethod()
呼叫,它返回,那么,方法的指数,通过它的签名字符串:
struct Q_CORE_EXPORT QMetaObject
{
// ... skip ...
int indexOfMethod(const char *method) const;
// ... skip ...
static void activate(QObject *sender, int signal_index, void **argv);
// ... skip ...
struct { // private data
const QMetaObject *superdata; // links to the parent class, I guess
const char *stringdata; // basically, "string1\0string2\0..." that contains signatures and other names
const uint *data; // the indices for the strings in stringdata and other stuff (e.g. flags)
// skip
} d;
};
现在时 moc
创造的 moc_headername.cpp
文件对脱类的头 headername.h
, 它把有签名字符串数据和其他数据所必需的正确的初始化 d
结构,并随后写的初始化时代码 staticMetaObject
单独使用这些数据。
另一个重要的事情,它是代码为对象的 qt_metacall()
方法,这需要对象的方法id和一系列参数的指针,并呼吁的方法,通过一个长长的 switch
是这样的:
int ClassName::qt_metacall(..., int _id, void **_args)
{
// ... skip ...
switch (_id) {
case 0: signalOrSlotMethod1(_args[1], _args[2]); break; // for a method with two args
case 1: signalOrSlotMethod2(_args[1]); break; // for a method with a single argument
// ... etc ...
}
// ... skip ...
}
最后,为每个信号 moc
产生一个执行情况,其中包含一个 QMetaObject::activate()
呼叫:
void ClassName::signalName(argtype1 arg1, argtype2 arg2, /* ... */)
{
void *_args[] = { 0, // this entry stands for the return value
&arg1, // actually, there's a (void*) type conversion
&arg2, // in the C++ style
// ...
};
QMetaObject::activate( this,
&staticMetaObject,
0, /* this is the signal index in the qt_metacall() map, I suppose */
_args
);
}
最后, connect()
呼叫翻译的字符串的方法的签名,他们整数id(的使用 qt_metacall()
)和维持一个列表中的信隙连接;当信号发射, activate()
代码就会通过该列表,并呼吁的适当对象"槽"通过他们的 qt_metacall()
法。
总的来说,静 QMetaObject
实例存"的元信息"方法(方法的签名字符串等),生成的 qt_metacall()
方法提供了"一个方法表",允许任何信号/槽被称为通过一个指数,信号的实现产生的 moc
使用这些指标通过 activate()
, 和最后 connect()
没有工作保持清单的信隙指数的地图。
*注意:有一种并发症,这个方案使用的情况下,当我们想要传递的信号之间不同的纹(I怀疑,有人要看 blocking_activate()
代码),但是我希望的普遍的想法仍然是相同)
这是我非常粗略的了解相联系的文章,这很容易可能是错误的,因此我建议去读它直接)
PS。因为我想提高我的理解脱执行情况-请让我知道的任何不一致之处在我复述!
因为我其他的(此前)的答案是删除一些热忱的编辑,我将追加的文字在这里(我失踪的几个细节 不 结合在帕维尔*Shved后,我怀疑的人被删除的答案的关心。)
@帕维尔*Shved:
我非常确定的地方在脱标题存在着一条线:
#define emit
只是来确认:发现它在旧脱码通过谷歌码检索。它是相当可能的,这是仍然存在);找到位置的路径是:
ftp://ftp.slackware-brasil.com.br" 要多得多-7.1" 普" kde-1.90" 脱-2.1.1.解压缩软" usr" lib" 脱-2.1.1" src" 内核" qobjectdefs.h
另一个complementory链接: http://lists.trolltech.com/qt-interest/2007-05/thread00691-0.html -看到答案由安德烈亚斯*Pakulat
这里是另一块的回答: 夸脱的问题:怎么做信号,并插槽工作?