The Book of QT4 翻译:1.3 信号和槽

25 篇文章 0 订阅


The Book of QT4 翻译:1.3 信号和槽




The Book of QT4 翻译


QT程序设计艺术


---------------------------------------------------------------------------------


原名:The Book of QT 4:The Art of Building Qt Applications


译名:The Book of QT 4中文版:QT程序设计艺术


译者:张小可 mcxiaoke@gmail.com


---------------------------------------------------------------------------------


第一章 基础,工具和第一行代码


 


***********************************************************************


**************************     1.3 信号和槽    *******************************
***********************************************************************


 


迄今为止讨论的程序仅仅产生输出。但是如果我们需要处理用户输入,没有对象间通信的话我们无法做到。


许多GUI工具包使用回调函数(callback functions)或者事件****(event listeners)来管理对象间通信,但是QT使用信号/槽(signal/slot)机制。与回调函数相比,信号槽机制的优势在于,当两个通信对象中的任意一个被删除时,QT可以自动断开连接。这避免了出错,简化了编程。


 


1.3.1 简单的案例:一个信号响应一个槽


 


要解释清楚对象如何通过信号和槽机制通信,最容易的方法是通过一个简单的例子。考虑下面这个程序,只是显示一个简单的文本为Quit的按钮。如果用户点击这个按钮,程序就会终止。


 


代码

    
    
1 // signalSlot/main.cpp 2   #include < QApplication > 3 #include < QPushButton > 4   int main( int argc, char * argv[]) 5 { 6 QApplication a(argc, argv); 7 QPushButton button( " Quit " ); 8 button.show(); 9 QObject::connect( & button, SIGNAL(clicked()), 10   & a, SLOT(quit())); 11   return a.exec(); 12 }
 
 

与第一节的HelloWorld程序相比,两个地方发生了变化。第一个就是上次使用的QLabel对象被一个QPushButton对象取代。QPushButton类用于显示一个鼠标可以点击的按钮。


第二个不同就是QObject::connect()方法的调用。connect()是QObject类的一个静态方法,用于创建来自于一个对象的信号与另一个目的对象的槽之间的连接。头两个参数指出了发射信号的对象和将要绑定到槽上的信号。后两个参数指出了接受信号的对象和槽。&符号是必须的因为connect()函数需要发射和接受对象的地址作为参数。这个函数确保当用户按下按钮时应用程序执行指定的行为:终止程序。


槽式一个有特殊标志的类的普通函数,因此可以对信号作出反应。从另一方面说,信号时对象发射的。某个对象发射的一个信号可以被连接至单个对象或多个不同对象的若干个槽。如果一个对象发射了一个信号,那么所有连接的槽都会被调用。如果没有相应的连接,什么都不会发生。


例子中对QObject::connect()方法的调用,连接了QPushButton对象的clicked()信号和QApplication对象的quit()槽。任何时候只要用户按下了按钮,按钮就会发现clicked()信号,这导致按钮的clicked()方法被调用。作为对这个信号的反应,QApplication对象的quit()方法被调用。调用这个槽结束了事件循环,因而也终止了整个程序。


当使用QObject::connect()方法连接信号和槽时,你必须使用两个宏:SIGNAL()和SLOT(),正如上面例子中展示的。对该方法的第二个(信号)和第四个(槽)参数来说,使用了SIGNAL和SLOT,是因为遵照QT的内部约定,connect()方法要求传递一个包含前缀的文本值,用于描述参数的类型(信号或槽)。使用这两个宏将确保产生的字符串符合要求。



1.3.2 信号携带的额外信息和工作机制


 


,信号和槽之间的连接可以用来传递额外的信息,这些信息可以控制槽对信号的精确反应。例如,在下面图1.6的例子中,这个例子包含了三个控件元素:一个显示数字的QLabel,一个可以用键盘或鼠标改变值的QSpinBox和一个图形化显示和控制当前值的QSlider。


我们的目的是让三个部件显示相同的值。如果用户通过滑块改变了值,那么值的改变必须立即反应在QSpinBox和QLabel上。如果用户改变了QSpinBox的值,同样必须反应在QSlider和QLabel上。下面是完整的代码:

代码

    
    
1 // signalSlot2/main.cpp 2   #include < QApplication > 3 #include < QVBoxLayout > 4 #include < QLabel > 5 #include < QSpinBox > 6 #include < QSlider > 7   int main( int argc, char * argv[]) 8 { 9 QApplication a(argc, argv); 10 QWidget window; 11 QVBoxLayout * mainLayout = new QVBoxLayout( & window); 12 QLabel * label = new QLabel( " 0 " ); 13 QSpinBox * spinBox = new QSpinBox; 14 QSlider * slider = new QSlider(Qt::Horizontal); 15 mainLayout -> addWidget(label); 16 mainLayout -> addWidget(spinBox); 17 mainLayout -> addWidget(slider); 18 QObject::connect(spinBox, SIGNAL(valueChanged( int )), 19 label, SLOT(setNum( int ))); 20 QObject::connect(spinBox, SIGNAL(valueChanged( int )), 21 slider, SLOT(setValue( int ))); 22 QObject::connect(slider, SIGNAL(valueChanged( int )), 23 label, SLOT(setNum( int ))); 24 QObject::connect(slider, SIGNAL(valueChanged( int )), 25 spinBox, SLOT(setValue( int ))); 26 window.show(); 27   return a.exec(); 28 } 29 30  

我们将三个部件依次摆放在一个垂直布局中。QSpinBox负责spin box元素,相应的,QSlider负责滑块。


为确保部件间的同步,我们使用了connect()方法。如果spin box的值改变了,那么标签和滑块的值必须更新;如果滑块的状态改变了,标签和spin box也必须实时更新。(注意:因为spinBox,label,slider变量已经是指向部件的指针变量,我们不需要像上一个例子中那样对它们使用&取地址操作。)

用户对值作出的更改会通过QSpinBox和QSlider类的信号QSpinBox::valueChanged(int)或QSlider::valueChanged(int)发送出去。在这两种情况下,int关键词标示的整数参数,通过信号传递给槽,指定了spin box或slider的新值。

label的新值使用QLabel::setNum(int)槽设置,该方法接受一个整数值作为参数。spin box和slider使用类似的方法更新值:QSpinBox::setValue(int)和 QSlider::setValue(int)。


图1.7的箭头显示一个信号可以被连接到多个槽,一个槽也可以对多个信号作出反应。例如,如果QSpinBox对象通过valueChanged(int)信号传递了值5,QLabel对象的setNum(int)槽和QSlider对象的setValue(int)槽就会以5为参数被调用。


QT没有指定槽对信号作出反应的顺序。无论是label还是slider首先被更新都是有可能的,精确的行为无法预测。然而,这三个部件最后将显示相同的值5。


在这个例子中,信号和槽使用相同的参数列表,因此在信号和槽的连接中没有发生类型转换。因此QLabel对象的setText()槽不能连接至valueChanged(int)信号,因为setText()需要一个字符串作为参数,但int类型的参数无法转换成字符串。


如果类型转换无法避免,你必须继承一个类并实现相应的槽。这个槽完成类型转换工作并调用实际的,对应的槽。因为槽实际上是一个类的普通方法,所以这是可能的。然后,反过来则是不行的:你不能将任何你喜欢的方法但做槽使用。因为槽必须特殊地标记以便QT可以检测和识别。第二章将详细讲述如何从QObject继承和定义自己的信号和槽。


即使信号和槽的连接不会自动调整参数类型,当一个槽要求的参数个数少于信号发射的参数个数时,你也可以将一个槽连接到这个信号;槽将简单的忽略多余的参数。从这个角度看,QSlider的valueChanged(int)信号可以被连接到QApplication对象的quit()槽。虽然这样做之后,当滑块的值一改变时程序就会立即终止(这个行为没什么用处),它显示了quit()忽略了信号发射的int参数。槽的参数类型必须与信号的参数类型一致。例如,你可以使用connect()将信号signalFoo(int, double)连接至槽slotFoo(), slotFoo(int)和slotFoo(int, double),但是不能将信号signalFoo(int, double)连接至槽slotFoo(double)。


如果你试图创建一个非法的信号-槽连接,编译器和连接器都不会报错。只是当应用程序运行时,你会看到一个警告:信号和槽连接不正确。例如,如果错误的connect()调用在我们先前的例子中执行,终端窗口会显示如下的警告:
Object::connect: Incompatible sender/receiver arguments
SomeClass::signalFoo(int,double) --> SomeClass::slotFoo(double)


如果槽要求的参数多余信号发射的,也将无法处理信号。因此,我们不能将信号signalFoo(int, double)连接至slotFoo(int,double, double)槽。



    
    
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值