
1、Qt的安装
首先去Qt的官方网站(http://qt.nokia.com/downloads)下载你所需要的安装包,官方提供了Windows、Linux、Mac OS等平台的安装包,这里我们选择Linux平台下的安装包。截至到目前为止,Qt的最新版本为4.7,所以我们下载所对应的安装包为qt-sdk-linux-x86-opensource-2010.05.1.bin。
下载完毕后我们打开超级终端,切换到root用户(sudo su),然后提升安装包的权限,使其具有执行权限,接着执行./ qt-sdk-linux-x86-opensource-2010.05.1.bin,弹出如下界面:
接着按照提示,一路next就可以了,安装完成后,接下来我们开始进入Qt的学习过程。
2、Qt的发展史
Qt的创建者Haarard Nord(Trolltech公司的CEO)和Eirik Chambe-Eng(Trolltech公司的总裁)是一家瑞典公司的同事。那时(1990)他们在做一个项目,这个项目需要在Unix,Macintosh,Windows上运行同一个GUI,象我们现在的开发人员一样,工作的很累,当时可是没有如今这么多的开发工具。一天他们工作之余去公园散步,晒太阳,喝咖啡。Haarard说:“We need an object-oriented display system。”这成为了后来Qt最重要的思想:提供面向对象的跨平台的GUI框架。看到这里小女我不仅感慨:什么时候我们的程序员们可以在工作的时候出来走走,只有在轻松愉快的环境中才会生产出出色的成果。在沉闷的办公室里,只是机械的堆砌代码而已。
所做就做,Haarard开始写代码,Eirik负责设计,Qt在襁褓中逐渐成长,在开始蹒跚学步的时候(1993年),他们开始让Qt闯荡江湖,两个人开始了创业的艰辛历程。
对这两个年轻人,1994年是非常艰难的一年,他们没有客户,没有钱,只有还没有完全实现的产品。关键时刻,他们的妻子帮他们渡过了难关。
字母Q作为所有类的前缀,是因为Haarard手写这个字母看起来特别的漂亮,字母t代表“toolkit”,在Xt, X toolkit等中得到灵感。
1995年开始出现转机,他们得到了一个合同。这一年,他们雇佣了Arnt Gulbrandsen,他在Trolltech工作了六年,他为Qt实现了优秀的文档系统。
1995年5月,Qt 0.9发布,有商业和开源两个版本。96年9月,Qt1.0发布。
1997年,Matthias Ettrich开始用Qt开发KDE,使Qt成为Linux上GUI开发的 事实上的标准。
1999年,Qt 2 发布。
2000年,Qtopia发布。支持linux嵌入式开发。
2001年,Qt 3 发布。
2005年, Qt 4 发布。
十年来,Qt就是这样从不知名的一个产品,发展到现在拥有全世界范围内成千上万的客户。
3、Qt入门
3.1从Hello Qt开始
差不多所有的程序教材都从Hello 开始,下面就是这个程序的qt版本。
首先向/etc/profile文件里添加如下内容
#set qt env
QT_HOME=/opt/qtsdk-2010.05/
PATH=$QT_HOME/qt/bin:$PATH
我的qt安装路径是/opt/qtsdk-2010.05/,请大家添加你自己的路径,这样下次重新启动电脑后,就可以使用qmake命令了。
使用VIM编辑器建立一个HelloQt.cpp文件,文件内容如下:
1 #include 2 #include 3 int main(int argc, char *argv[]) 4 { 5 QApplication app(argc, argv); 6 QLabel *label = new QLabel("Hello Qt!"); 7 label->show(); 8 return app.exec(); 9 } 按行解析以上9行代码 第一,二行:是代码中需要使用的类的头文件。在Qt4中,可以写成 第三行:是main函数的标准写法 第五行:创建一个QApplication对象,管理应用程序的资源。 第六行:QLabel对象,QLabel是一个Qt提供的小控件,显示一行文本。 第七行:显示QLabel。 第八行:QApplication.exec(),让程序进入消息循环。等待可能的菜单,工具条,鼠标等的输入,进行响应。 打开终端,进入HelloQt.cpp所在目录,执行: qmake –project qmake make 执行完所有的命令后,再执行./HelloQt,出现如下界面 第6行代码还可以如下替换: QLabel *label = new QLabel(" "Qt!"); 这里面包含了html文本,显示的字体,颜色会改变,运行结果如下: 实际程序中,下面两行是比不可少的。 QApplication app(argc, argv); return app.exec(); 3.2建立连接 这个例子用来说明怎么响应信号,和hello程序的源代码相似,原来的Label用一个按钮代替,点击时退出程序。 源程序如下: 1 #include 2 #include 3 int main(int argc, char *argv[]) 4 { 5 QApplication app(argc, argv); 6 QPushButton *button = new QPushButton("Quit"); 7 QObject::connect(button, SIGNAL(clicked()), 8 &app, SLOT(quit())); 9 button->show(); 10 return app.exec(); 11 } 当有所动作或者状态改变,qt的控件会发出消息(signal),例如,当点击按钮时,按钮会发送clicked()消息,这个消息可以连接到一个函数上(这个函数在这里成为slot)。这样,当一个消息发送时,slot函数可以自动执行。在这个例子中,我们连接了按钮的clicked信号和QApplication的quit函数,语法如第七,八行所示。 然后运行程序,点击Quit按钮,程序将会中止。 4创建对话框(Creating Dialogs) 在这章介绍如何创建Qt的对话框。对话框是程序和用户交互的桥梁,提供了程序和用户之间对话的一种方式。 很多程序都是由一个主窗口,在这个主窗口中包含一个菜单条,多个工具条,和足够多的对话框。也有些程序本身就是一个对话框,直接相应用户的输入请求。 本章中我们首先会用代码的方式创建我们的第一个对话框,然后用Qt Designer工具创建对话框。Qt Designer是一个可视化的工具,用它可以更快的创建,修改对话框。 4.1派生对话框类(Subclassing QDialog) 第一个例子是一个用C++实现的查找对话框。我们把这个对话框实现为一个类,这样它就是一个的控件,并有自己的信号(signal)和slot函数 类的源代码分别放在finddialog.h和finddialog.cpp中。首先看finddialog.h的代码 1 #ifndef FINDDIALOG_H 2 #define FINDDIALOG_H 3 #include 4 class QCheckBox; 5 class QLabel; 6 class QLineEdit; 7 class QPushButton; 8 class FindDialog : public QDialog 9 { 10 Q_OBJECT 11 public: 12 FindDialog(QWidget *parent = 0); 13 signals: 14 void findNext(const QString &str, Qt::CaseSensitivity cs); 15 void findPrevious(const QString &str, Qt::CaseSensitivity cs); 16 private slots: 17 void findClicked(); 18 void enableFindButton(const QString &text); 19 private: 20 QLabel *label; 21 QLineEdit *lineEdit; 22 QCheckBox *caseCheckBox; 23 QCheckBox *backwardCheckBox; 24 QPushButton *findButton; 25 QPushButton *closeButton; 26 }; 27 #endif 一共27行,第1,2,27行是为了避免头文件被多次包含。 第3行包含QDialog头文件,这个类从QDialog继承,QDialog从QWidget继承。 第4至7行是用到的Qt中类的前向声明。通过前向声明,编译器就知道这个类已经存在,而不用写出包含的头文件。这个问题稍后还要讲。 第8至26行是类FindDialog的定义。 第10行,Q_OBJECT是一个宏定义,如果类里面用到了signal或者slots,就要声明这个宏。 第12行, FindDialog(QWidget *parent = 0);构造函数是Qt控件类的标准格式,默认的父参数为NULL,说明没有父控件。 第13行,signal声明了这个对话框发出的两个信号,如果选择向前查找,那么对话框就发出findPrevious()信号,否则,发出findNext()信号。signal也是一个宏,在编译之前,C++预处理把它变成标准的c++代码。Qt::CaseSensitivity是一个枚举类型,有Qt::CaseSensitive和Qt::CaseInsensitive两个值。 在类的私有部分,声明有两个slot函数。为了实现这两个函数,需要用到对话框的其他控件的信息,所以保存了一些控件的指针。slot关键字和signal一样,也是一个宏。 对于私有成员变量,我们只是使用了它们的指针,没有对它们进行存取操作,编译器不需要知道它们的详细定义,所以只使用了这些类的前向声明。当然,也可以使用 下面看一下finddialog.cpp源文件代码: 文件头和构造函数部分 1 #include 2 #include "finddialog.h" 3 FindDialog::FindDialog(QWidget *parent) 4 : QDialog(parent) 5 { 6 label = new QLabel(tr("Find &what:")); 7 lineEdit = new QLineEdit; 8 label->setBuddy(lineEdit); 9 caseCheckBox = new QCheckBox(tr("Match &case")); 10 backwardCheckBox = new QCheckBox(tr("Search &backward")); 11 findButton = new QPushButton(tr("&Find")); 12 findButton->setDefault(true); 13 findButton->setEnabled(false); 14 closeButton = new QPushButton(tr("Close")); 15 connect(lineEdit, SIGNAL(textChanged(const QString &)), 16 this, SLOT(enableFindButton(const QString &))); 17 connect(findButton, SIGNAL(clicked()), 18 this, SLOT(findClicked())); 19 connect(closeButton, SIGNAL(clicked()), 20 this, SLOT(close())); 21 QHBoxLayout *topLeftLayout = new QHBoxLayout; 22 topLeftLayout->addWidget(label); 23 topLeftLayout->addWidget(lineEdit); 24 QVBoxLayout *leftLayout = new QVBoxLayout; 25 leftLayout->addLayout(topLeftLayout); 26 leftLayout->addWidget(caseCheckBox); 27 leftLayout->addWidget(backwardCheckBox); 28 QVBoxLayout *rightLayout = new QVBoxLayout; 29 rightLayout->addWidget(findButton); 30 rightLayout->addWidget(closeButton); 31 rightLayout->addStretch(); 32 QHBoxLayout *mainLayout = new QHBoxLayout; 33 mainLayout->addLayout(leftLayout); 34 mainLayout->addLayout(rightLayout); 35 setLayout(mainLayout); 36 setWindowTitle(tr("Find")); 37 setFixedHeight(sizeHint().height()); 38 } 在第4行,把parent参数传递给了基类的构造函数。然后,创建了子窗口部件。在字符串周围的tr()函数调用的是把它们翻译成其他语言的标记。 在这些字符串中,使用了“&”来表示快捷键。例如,第11行创建了一个Find按钮,用户可在那些支持快捷键的平台下通过按下Alt+F快捷键来激活它。符号“&”可以用来控制焦点:在第六行创建一个带有快捷(Alt+W)的标签,而在第8行设置了行编辑器作为标签的伙伴,所谓“伙伴”(buddy),就是一个窗口部件,它可以在按下标签的快捷键时接受焦点(focus)。所以当用户按下Alt+W(该标签的快捷键)时,焦点就会移动到这个行编辑器上。 到这里FindDialog的构造函数就完成了。在传见控件和布局时我们使用了new,一般情况下,我们还需要写析构函数delete这些控件。 但是在Qt中这是不需要的,当父控件销毁时,Qt自动删除它所有的子控件和布局。 下面是FindDialog类的两个slot函数: 39 void FindDialog::findClicked() 40 { 41 QString text = lineEdit->text(); 42 Qt::CaseSensitivity cs = 43 caseCheckBox->isChecked() ? Qt::CaseSensitive 44 : Qt::CaseInsensitive; 45 if (backwardCheckBox->isChecked()) { 46 emit findPrevious(text, cs); 47 } else { 48 emit findNext(text, cs); 49 } 50 } 51 void FindDialog::enableFindButton(const QString &text) 52 { 53 findButton->setEnabled(!text.isEmpty()); 54 } 当用户点击findButton按钮,findClicked()就会调用,根据backwardCheckBox状态,他发出findPrevious()或者findNext()信号。emit也是一个Qt的宏。 当用户改变lineEdit中的文本,enableFindButton()slot函数就会调用。如果输入了文本,那么让findButton有效,否则就无效。 最后,创建main.cpp测试FindDialog对话框。 1 #include 2 #include "finddialog.h" 3 int main(int argc, char *argv[]) 4 { 5 QApplication app(argc, argv); 6 FindDialog *dialog = new FindDialog; 7 dialog->show(); 8 return app.exec(); 9 } 程序运行结果如下: 运行程序,如果看到了快键,测试ALT+W,ALT+C,ALT+B,ALT+F引发相应的处理程序。使用TAB键在将焦点改变到不同的控件上。默认的TAB键是控件创建的顺序。QWidget::setTabOrder()可以改变这个顺序。 提供合适的tab顺序和快键可以让用户不用鼠标也可以运行程序,通过键盘可以快速控制程序。 4.2深入信号和槽(Signals and Slots in Depth) 信号和槽机制是 QT 的核心机制,要精通 QT 编程就必须对信号和槽有所了解。信号和槽是一种高级接口,应用于对象之间的通信,它是 QT 的核心特性,也是 QT 区别于其它工具包的重要地方。信号和槽是 QT 自行定义的一种通信机制,它于标准的 C/C++ 语言,因此要正确的处理信号和槽,必须借助一个称为 moc(Meta Object Compiler)的 QT 工具,该工具是一个 C++ 预处理程序,它为高层次的事件处理自动生成所需要的附加代码。 在我们所熟知的很多 GUI 工具包中,窗口小部件 (widget) 都有一个回调函数用于响应它们能触发的每个动作,这个回调函数通常是一个指向某个函数的指针。但是,在 QT 中信号和槽取代了这些凌乱的函数指针,使得我们编写这些通信程序更为简洁明了。 信号和槽能携带任意数量和任意类型的参数,他们是类型完全安全的,不会像回调函数那样产生 core dumps。 所有从 QObject 或其子类 ( 例如 Qwidget) 派生的类都能够包含信号和槽。当对象改变其状态时,信号就由该对象发射 (emit) 出去,这就是对象所要做的全部事情,它不知道另一端是谁在接收这个信号。这就是真正的信息封装,它确保对象被当作一个真正的软件组件来使用。槽用于接收信号,但它们是普通的对象成员函数。一个槽并不知道是否有任何信号与自己相连接。而且,对象并不了解具体的通信机制。 你可以将很多信号与单个的槽进行连接,也可以将单个的信号与很多的槽进行连接,甚至于将一个信号与另外一个信号相连接也是可能的,这时无论第一个信号什么时候发射系统都将立刻发射第二个信号。总之,信号与槽构造了一个强大的部件编程机制。 信号 当某个信号对其客户或所有者发生的内部状态发生改变,信号被一个对象发射。只有 定义过这个信号的类及其派生类能够发射这个信号。当一个信号被发射时,与其相关联的槽将被立刻执行,就象一个正常的函数调用一样。信号 - 槽机制完全于任何 GUI 事件循环。只有当所有的槽返回以后发射函数(emit)才返回。 如果存在多个槽与某个信号相关联,那么,当这个信号被发射时,这些槽将会一个接一个地 执行,但是它们执行的顺序将会是随机的、不确定的,我们不能人为地指定哪个先执行、哪 个后执行。 信号的声明是在头文件中进行的,QT 的 signals 关键字指出进入了信号声明区,随后即可 声明自己的信号。例如,下面定义了三个信号: signals: void mySignal(); void mySignal(int x); 信号由 moc 自动产生,它们不应该在 .cpp 文件中实现。 槽 槽是普通的 C++ 成员函数,可以被正常调用,它们唯一的特殊性就是很多信号可以与其相关联。当与其关联的信号被发射时,这个槽就会被调用。槽可以有参数,但槽的参数不能有缺省值。 既然槽是普通的成员函数,因此与其它的函数一样,它们也有存取权限。槽的存取权限决定了谁能够与其相关联。同普通的 C++ 成员函数一样,槽函数也分为三种类型,即 public slots、private slots 和 protected slots。 ∙public slots:在这个区内声明的槽意味着任何对象都可将信号与之相连接。这对于组件编程非常有用,你可以创建彼此互不了解的对象,将它们的信号与槽进行连接以便信息能够正确的传递。 ∙protected slots:在这个区内声明的槽意味着当前类及其子类可以将信号与之相连接。这适用于那些槽,它们是类实现的一部分,但是其界面接口却面向外部。 ∙private slots:在这个区内声明的槽意味着只有类自己可以将信号与之相连接。这适用于联系非常紧密的类。 ∙ 槽也能够声明为虚函数,这也是非常有用的。 槽的声明也是在头文件中进行的。例如,下面声明了三个槽: public slots: void mySlot(); void mySlot(int x); 通过调用 QObject 对象的 connect 函数来将某个对象的信号与另外一个对象的槽函数相关联,这样当发射者发射信号时,接收者的槽函数将被调用。该函数的定义如下: bool QObject::connect ( const QObject * sender, const char * signal, 例如,下面定义了两个对象:标签对象 label 和滚动条对象 scroll,并将 valueChanged() 信号与标签对象的 setNum() 相关联,另外信号还携带了一个整形参数,这样标签总是显示滚动条所处位置的值。 QLabel *label = new QLabel; QScrollBar *scroll = new QScrollBar; QObject::connect( scroll, SIGNAL(valueChanged(int)), class MyWidget : public QWidget { public: MyWidget(); ... signals: void aSignal(); ... private: ... QPushButton *aButton; }; MyWidget::MyWidget() { aButton = new QPushButton( this ); connect(aButton,SIGNAL(clicked()), SIGNAL(aSignal()) ); 当信号与槽没有必要继续保持关联时,我们可以使用 disconnect 函数来断开连接。其定义如下: bool QObject::disconnect ( const QObject * sender, const char * signal, 有三种情况必须使用 disconnect() 函数: ∙断开与某个对象相关联的任何对象。这似乎有点不可理解,事实上,当我们在某个对象中定义了一个或者多个信号,这些信号与另外若干个对象中的槽相关联,如果我们要切断这些关联的话,就可以利用这个方法,非常之简洁。 disconnect( myObject, 0, 0, 0 ) 或者 disconnect( myObject, SIGNAL(mySignal()), 0, 0 ) 或者 disconnect( myObject, 0, myReceiver, 0 ) 或者 元对象工具 元对象编译器 moc(meta object compiler)对 C++ 文件中的类声明进行分析并产生用于初始化元对象的 C++ 代码,元对象包含全部信号和槽的名字以及指向这些函数的指针。 moc 读 C++ 源文件,如果发现有 Q_OBJECT 宏声明的类,它就会生成另外一个 C++ 源文件,这个新生成的文件中包含有该类的元对象代码。例如,假设我们有一个头文件 mysignal.h,在这个文件中包含有信号或槽的声明,那么在编译之前 moc 工具就会根据该文件自动生成一个名为 mysignal.moc.h 的 C++ 源文件并将其提交给编译器;类似地,对应于 mysignal.cpp 文件 moc 工具将自动生成一个名为 mysignal.moc.cpp 文件提交给编译器。 元对象代码是 signal/slot 机制所必须的。用 moc 产生的 C++ 源文件必须与类实现一起进行编译和连接,或者用 #include 语句将其包含到类的源文件中。moc 并不扩展 #include 或者 #define 宏定义 , 它只是简单的跳过所遇到的任何预处理指令。 应注意的问题 信号与槽机制是比较灵活的,但有些局限性我们必须了解,这样在实际的使用过程中做到有的放矢,避免产生一些错误。下面就介绍一下这方面的情况。 1 .信号与槽的效率是非常高的,但是同真正的回调函数比较起来,由于增加了灵活性,因此在速度上还是有所损失,当然这种损失相对来说是比较小的,通过在一台 i586-133 的机器上测试是 10 微秒(运行 Linux),可见这种机制所提供的简洁性、灵活性还是值得的。但如果我们要追求高效率的话,比如在实时系统中就要尽可能的少用这种机制。 2 .信号与槽机制与普通函数的调用一样,如果使用不当的话,在程序执行时也有可能产生死循环。因此,在定义槽函数时一定要注意避免间接形成无限循环,即在槽中再次发射所接收到的同样信号。例如 , 在前面给出的例子中如果在 mySlot() 槽函数中加上语句 emit mySignal() 即可形成死循环。 3 .如果一个信号与多个槽相联系的话,那么,当这个信号被发射时,与之相关的槽被激活的顺序将是随机的。 4. 宏定义不能用在 signal 和 slot 的参数中。 既然 moc 工具不扩展 #define,因此,在 signals 和 slots 中携带参数的宏就不能正确地工作,如果不带参数是可以的。例如,下面的例子中将带有参数的宏 SIGNEDNESS(a) 作为信号的参数是不合语法的: #ifdef ultrix #define SIGNEDNESS(a) unsigned a #else #define SIGNEDNESS(a) a #endif class Whatever : public QObject { [...] signals: void someSignal( SIGNEDNESS(a) ); [...] 的确,将一个构造函数放在 signals 或者 slots 区内有点不可理解,无论如何,不能将它们放在 private slots、protected slots 或者 public slots 区内。下面的用法是不合语法要求的: class SomeClass : public QObject { Q_OBJECT public slots: SomeClass( QObject *parent, const char *name ) : QObject( parent, name ) {} // 在槽声明区内声明构造函数不合语法 [...] 例如,下面的例子中将 void (*applyFunction)(QList*, void*) 作为参数是不合语法的: class someClass : public QObject { Q_OBJECT [...] public slots: void apply(void (*applyFunction)(QList*, void*), char*); // 不合语法 typedef void (*ApplyFunctionType)(QList*, void*); class someClass : public QObject { Q_OBJECT [...] public slots: void apply( ApplyFunctionType, char *); 既然 signal->slot 绑定是发生在运行时刻,那么,从概念上讲使用缺省参数是困难的。下面的用法是不合理的: class SomeClass : public QObject { Q_OBJECT public slots: void someSlot(int x=100); // 将 x 的缺省值定义成 100,在槽函数声明中使用是错误的 如果将信号、槽声明为模板类参数的话,即使 moc 工具不报告错误,也不可能得到预期的结果。 例如,下面的例子中当信号发射时,槽函数不会被正确调用: [...] public slots: void MyWidget::setLocation (pair [...] public signals: typedef pair [...] public slots: void MyWidget::setLocation (IntPair location); [...] public signals: 9. 嵌套的类不能位于信号或槽区域内,也不能有信号或者槽。 例如,下面的例子中,在 class B 中声明槽 b() 是不合语法的,在信号区内声明槽 b() 也是不合语法的。 class A { Q_OBJECT public: class B { public slots: // 在嵌套类中声明槽不合语法 void b(); [....] }; signals: class B { // 在信号区内声明嵌套类不合语法 void b(); [....] }: 相反,它们应该在普通 C++ 的 private、protected 或者 public 区内进行声明。下面的例子是不合语法规范的: class someClass : public QObject { Q_OBJECT [...] signals: // 信号定义区 friend class ClassTemplate; // 此处定义不合语法 Qt Creator 是 Qt 被 Nokia 收购后推出的一款新的轻量级集成开发环境(IDE)。此 IDE 能够跨平台运行,支持的系统包括 Linux(32位及 位)、Mac OS X 以及 Windows。根据官方描述,Qt Creator 的设计目标是使开发人员能够利用 Qt 这个应用程序框架更加快速及轻易的完成开发任务。 在功能方面,Qt Creator 包括项目生成向导、高级的 C++ 代码编辑器、浏览文件及类的工具、集成了 Qt Designer、图形化的 GDB 调试前端,集成 qmake 构建工具等。 Qt Creator的主界面如下(所有平台的Qt Creator基本是一模一样的使用): 5.1使用Qt Creator创建空的Qt应用程序 单击菜单栏上的File->New File or Project,出现下面的对话框: 我们选择Other Project下面的Empty Qt Project,单击Choose 在Name中我们输入test1(注意Name可以随便起,但是不应包含空格),然后选择项目的创建位置,单击Next 单击Finish,出现如下界面: 我们一般单击Finish就可以了,至此我们的工程就创建好了: 接下来我们向工程中添加文件,右击test1,单击Add New,出现如下界面: 我们选择C++ Source File,单击Choose: 接下来给你的文件取个名字,这里我们填入test1,单击Next: 一般默认就行,单击Finish,添加文件完毕: 可以看到test1.cpp添加到了工程中了,我们在test1.cpp中写入如下内容: #include #include int main(int argc, char* argv[]) { QApplication app(argc, argv); QLabel* label=new QLabel("Hello Qt"); label->show(); return app.exec(); } 单击菜单栏上的Build->Build All,然后单击Build->Run就可以运行程序了: 5.2使用Qt Creator创建Qt图形界面应用程序 单击菜单栏上的File->New File or Project,出现下面的对话框: 选择Qt C++ Project下面的Qt Gui Application,单击Choose,出现如下界面: 单击Next: 接下来基本按照提示就可以了,建立后的工程如下: 我们可以看到比一般手动写的工程多出一个mainwindow.ui文件 ,这是什么东西呢?我们双击这个文件,发现跳转到了Qt Designer Qt Designer的具体用法可以参考自带的帮助文档Assitant–>Content–>Qt Designer Manual。 我们直接编译运行工程,结果如下:Hello "
在上面的定义中,signals 是 QT 的关键字,而非 C/C++ 的。接下来的一行 void mySignal() 定义了信号 mySignal,这个信号没有携带参数;接下来的一行 void mySignal(int x) 定义 了重名信号 mySignal,但是它携带一个整形参数,这有点类似于 C++ 中的虚函数。从形式上 讲信号的声明与普通的 C++ 函数是一样的,但是信号却没有函数体定义,另外,信号的返回 类型都是 void,不要指望能从信号返回什么有用信息。 void mySignalParam(int x,int y);
信号与槽的关联 void mySignalParam(int x,int y);
这个函数的作用就是将发射者 sender 对象中的信号 signal 与接收者 receiver 中的 member 槽函数联系起来。当指定信号 signal 时必须使用 QT 的宏 SIGNAL(),当指定槽函数时必须使用宏 SLOT()。如果发射者与接收者属于同一个对象的话,那么在 connect 调用中接收者参数可以省略。 const QObject * receiver, const char * member ) [static]
一个信号甚至能够与另一个信号相关联,看下面的例子: label, SLOT(setNum(int)) );
在上面的构造函数中,MyWidget 创建了一个私有的按钮 aButton,按钮的单击事件产生的信号 clicked() 与另外一个信号 aSignal() 进行了关联。这样一来,当信号 clicked() 被发射时,信号 aSignal() 也接着被发射。当然,你也可以直接将单击事件与某个私有的槽函数相关联,然后在槽中发射 aSignal() 信号,这样的话似乎有点多余。 }
这个函数断开发射者中的信号与接收者中的槽函数之间的关联。 const Object * receiver, const char * member ) [static]
∙断开与某个特定信号的任何关联。 myObject->disconnect()
∙断开两个对象之间的关联。 myObject->disconnect( SIGNAL(mySignal()) )
在 disconnect 函数中 0 可以用作一个通配符,分别表示任何信号、任何接收对象、接收对象中的任何槽函数。但是发射者 sender 不能为 0,其它三个参数的值可以等于 0。 myObject->disconnect( myReceiver )
5. 构造函数不能用在 signals 或者 slots 声明区域内。 };
6. 函数指针不能作为信号或槽的参数。 };
你可以采用下面的方法绕过这个: };
7. 信号与槽不能有缺省参数。 };
8. 信号与槽也不能携带模板类参数。 };
但是,你可以使用 typedef 语句来绕过这个。如下所示: void MyObject::moved (pair
这样使用的话,你就可以得到正确的结果。 void MyObject::moved (IntPair location);
10. 友元声明不能位于信号或者槽声明区内。 };
5、使用Qt Creator创建应用程序 };
