QT 的信号与槽机制介绍(3)

元对象代码是 signal/slot 机制所必须的。用 moc 产生的 C++ 源文件必须与类实现一起进行编译和连接,或者用 #include 语句将其包含到类的源文件中。moc 并不扩展 #include 或者 #define 宏定义 , 它只是简单的跳过所遇到的任何预处理指令。

程序样例

这里给出了一个简单的样例程序,程序中定义了三个信号、三个槽函数,然后将信号与槽进行了关联,每个槽函数只是简单的弹出一个对话框窗口。读者可以用 kdevelop 生成一个简单的 QT 应用程序,然后将下面的代码添加到相应的程序中去。

信号和槽函数的声明一般位于头文件中,同时在类声明的开始位置必须加上 Q_OBJECT 语句,这条语句是不可缺少的,它将告诉编译器在编译之前必须先应用 moc 工具进行扩展。关键字 signals 指出随后开始信号的声明,这里 signals 用的是复数形式而非单数,siganls 没有 public、private、protected 等属性,这点不同于 slots。另外,signals、slots 关键字是 QT 自己定义的,不是 C++ 中的关键字。

信号的声明类似于函数的声明而非变量的声明,左边要有类型,右边要有括号,如果要向槽中传递参数的话,在括号中指定每个形式参数的类型,当然,形式参数的个数可以多于一个。

关键字 slots 指出随后开始槽的声明,这里 slots 用的也是复数形式。

槽的声明与普通函数的声明一样,可以携带零或多个形式参数。既然信号的声明类似于普通 C++ 函数的声明,那么,信号也可采用 C++ 中虚函数的形式进行声明,即同名但参数不同。例如,第一次定义的 void mySignal() 没有带参数,而第二次定义的却带有参数,从这里我们可以看到 QT 的信号机制是非常灵活的。

信号与槽之间的联系必须事先用 connect 函数进行指定。如果要断开二者之间的联系,可以使用函数 disconnect。

//tsignal.h
 ...
 class TsignalApp:public QMainWindow
 {
  Q_OBJECT
  ...
  // 信号声明区
  signals:
  // 声明信号 mySignal()
  void mySignal();
  // 声明信号 mySignal(int)
  void mySignal(int x);
  // 声明信号 mySignalParam(int,int)
  void mySignalParam(int x,int y);
  // 槽声明区
  public slots:
  // 声明槽函数 mySlot()
  void mySlot();
  // 声明槽函数 mySlot(int)
  void mySlot(int x);
  // 声明槽函数 mySignalParam (int,int)
  void mySignalParam(int x,int y);
 }
 ...
 //tsignal.cpp
 ...
 TsignalApp::TsignalApp()
 {
  ...
  // 将信号 mySignal() 与槽 mySlot() 相关联
  connect(this,SIGNAL(mySignal()),SLOT(mySlot()));
  // 将信号 mySignal(int) 与槽 mySlot(int) 相关联
  connect(this,SIGNAL(mySignal(int)),SLOT(mySlot(int)));
  // 将信号 mySignalParam(int,int) 与槽 mySlotParam(int,int) 相关联
  connect(this,SIGNAL(mySignalParam(int,int)),SLOT(mySlotParam(int,int)));
 }
 // 定义槽函数 mySlot()
 void TsignalApp::mySlot()
 {
  QMessageBox::about(this,"Tsignal", "This is a signal/slot sample without
 parameter.");
 }
 // 定义槽函数 mySlot(int)
 void TsignalApp::mySlot(int x)
 {
  QMessageBox::about(this,"Tsignal", "This is a signal/slot sample with one
 parameter.");
 }
 // 定义槽函数 mySlotParam(int,int)
 void TsignalApp::mySlotParam(int x,int y)
 {
  char s[256];
  sprintf(s,"x:%d y:%d",x,y);
  QMessageBox::about(this,"Tsignal", s);
 }
 void TsignalApp::slotFileNew()
 {
  // 发射信号 mySignal()
  emit mySignal();
  // 发射信号 mySignal(int)
  emit mySignal(5);
  // 发射信号 mySignalParam(5,100)
  emit mySignalParam(5,100);
 }

应注意的问题

信号与槽机制是比较灵活的,但有些局限性我们必须了解,这样在实际的使用过程中做到有的放矢,避免产生一些错误。下面就介绍一下这方面的情况。

1 .信号与槽的效率是非常高的,但是同真正的回调函数比较起来,由于增加了灵活性,因此在速度上还是有所损失,当然这种损失相对来说是比较小的,通过在一台 i586-133 的机器上测试是 10 微秒(运行 Linux),可见这种机制所提供的简洁性、灵活性还是值得的。但如果我们要追求高效率的话,比如在实时系统中就要尽可能的少用这种机制。

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/7aac900bd6608b6bcc93cff550dc1e56.html