首页资源分类嵌入式系统 > QT实战开发

QT实战开发

已有 445110个资源

下载专区

上传者其他资源

    文档信息举报收藏

    标    签:QT实战开发

    分    享:

    文档简介

    基于QT的实战开发例程,对初学非常有帮助

    文档预览

    基于嵌入式 Linux 的 Qt 图形程序实战开发 奚海蛟 谌利 吕铁军 编著 达内 IT 培训集团 审校 北京航空航天大学出版社 前言 在 linux 系统中,有很多可供选择的 GUI 库,其中 Qt 是比较流行的一个。Qt 是一个完 整的 C++应用程序开发框架。从宏观上来看,Qt 就是用 C++写的一些类库。要用类库创建 界面,需要实例化相应的类构造出窗口部件,由窗口部件构建界面。 本书的主要内容 第一章认识 Qt。主要介绍了 Qt 的相关概念,Qt 不同的版本,Qt 安装在不同的平台上。 开发嵌入式的 Qt 应用软件时,需要建立的交叉编译环境。最后一小节,通过 Hello Qt 的文 本显示,简单的了解了一下 Qt 的开发以及编译流程。 第二章信号与槽。主要介绍了信号与槽的实现机制。信号与槽机制是 Qt 的核心机制, 信号与槽的关联通过调用 QObject 对象的 connect 函数来将某个对象的信号与另外一个对 象的槽函数相关联,这样当发射者发射信号时,接收者的槽函数将被调用。并通过实例介绍 了信号和槽的创建和使用方法,最后介绍了信号与槽需要注意的问题。 第三章对话框设计。主要介绍了 Qt 中最常见的对话框类。其中包括如何自定义对话框 以及内建对话框的使用。对话框几乎贯穿整个学习过程,在常用软件中会经常出现,通过几 个例子介绍了它们的使用方法。 第四章创建主窗口。主要介绍了应用程序主窗口框架的组成:菜单栏、工具栏、锚接窗 口、中心部件、状态栏。常用的创建主窗口的方法,以及其优缺点和适用场合;完全使用代 码创建主窗口的方法和步骤;一些有关窗口部件的知识。 第五章自定义窗口部件。主要介绍了如何通过 Qt 类库中提供的多种类,子类化出相应 的窗口部件。另外介绍从 QWidget 基类直接开始继承,创造出自己的窗口部件。但一般提 倡使用 Qt 库中提供的已经存在的比较完善的类库,不提倡自己创建。在本章的最后介绍双 缓冲技术,双缓冲技术是用来优化绘制事件的显示。 第六章部件布局。主要介绍了 GUI 编程不可缺少的部分——Qt 布局管理,即使再简单 的程序,也需要有合理的布局,否则界面将失去价值。在本章详细介绍了 Qt 中的布局管理, 其中涉及到的布局管理类有布局管理器、分裂器、栈部件以及工作空间。其实多文档属于布 局管理,在第十三章中详细介绍。 第七章文本输入和表。主要介绍了 Qt 中的基本的文本输入控件,主要包括 QComboBox、 QLineEdit、QTextEdit。并介绍了 QTableView 类的子类 QTableWidget 类和 QTableWidgetItem 类,本章通过自己构造一个简单的单元格模型类 Cell 来介绍其有关各类的详细属性、成员 函数可参考 Qt 4.7 帮助文档。 第八章容器类。主要介绍了 Qt 提供的属于自己的容器类。这些容器类用于在内存中存 储给定类型的许多项。这些容器包括类似于数组和链表的连续容器,包括 QVector、 QLinkedList和 QList,还有可以存储的带索引的关联容器,包括 QMap和 QHash等。另外简单介绍了之类似的类 QString、QByteArray 和 QVariant。最后介绍 了 Qt 对所有的容器和许多类都使用的隐含共享。 第九章目录与文件处理。主要介绍了 Qt 提供的通用的文件处理类 QFile 以及处理文本 的 QTextStream 和处理二进制数据的 QDataStream 类,这些流操作极大地方便了对文件的读 取存储。对文件信息和目录进行操作的类是 QFilelno 和 QDir。要监视文件和目录变化,则 可以使用 QFileSystemWatcher 类。 第十章 Qt 中的事件机制。主要介绍了鼠标事件、键盘事件、事件过滤器和时间事件, 并通过实例介绍了相关的应用,还分析了系统繁忙时的事件响应处理。 第十一章二维图形的绘制。主要介绍了 Qt 的 2D 绘图功能,包括的三个核心类 QPainter、 QPaintEngine、QPaintDevice,从绘图函数、图像处理、绘图路径、渐变画刷、纹理画刷等 方面进行了详细介绍,及处理图像的 4 个类 QImage、QPixmap、QBitmap、QPictrue。简单 介绍了 QPainter 的坐标系统,和几个常用的坐标变化函数。 第十二章 MDI 程序设计。主要介绍了 QMainWindow 类使用方式中的 MDI(多文档界 面),了解多文档界面的实现步骤和结构。两种工作区类 QWorkSpace 和 QMdiArea,两类使 用很相似。本章实例使用 QMdiArea 类来实现了一个简单的文本编辑器 MDI 程序的。通过 此程序介绍了 MDI 程序的结构和实现步骤,和子窗口的管理。 第十三章 Model/View 结构。主要介绍了处理数据集的标准方式。用到了从 MVC 模式发 展过来的模型/视图模式。详细介绍了 model/view 的结构关系,model 类、view 类和 delegate 类各类之间的关系,以及 model、view 和 delegate 的常见到的子类。从 model 中选择数据到 view 中显示,而 delegate 用于处理与用户的交互。 第十四章 Qt 的网络编程。主要介绍了 Qt 中 NETWORK 的及整个重要的应用,首 先是最上层的 HTTP 和 FTP,然后就是这两个应用的基础 TCP/IP,了解了它们的通信 原理以及 Qt 编程的方法。这些内容由浅入深的讲了网络编程的方法和原理。 第十五章数据库程序设计。主要介绍了数据库的基本操作以及数据库的模型的应用。 第十六章 Qt 多线程程序设计。主要介绍了 Qt 中的线程是如何应用的,通过实例分析了 进程间的同步与互斥机制,并介绍了优先级与死锁的该概念。 第十七章 Qt4.5 在 S3C2440 上的移植和程序的调试和发布。主要介绍了交叉编译链的制 作与移植,Qt 程序的调试技术和应用程序的编译。 读者对象 本书是一本基于 Linux 嵌入式 Qt 开发的相关书籍,适合于以下读者:  刚接触 Qt 的初学者。  对 Qt 开发感兴趣的人员。  使用 S3C2440 开发产品的程序员和开发人员  从事 Qt 开发的科研人员。  从事 Qt 相关教育的老师。 相关软件 本书提到的很多软件是 GNU 软件,可以在互联网上免费获取。 Qt 相关开发工具可以从 Qt 官网上下载,http://qt.nokia.com 。或者从 QTCN 论坛上下 载,http://www.qtcn.org/bbs/read.php?tid=1075 。 由于编者水平有限,错误之处在所难免,敬请广大读者、师生批评指正。 编者 2012.3 内容简介 本书共分为十七章,分别从信号与槽、对话框、主窗口、自定义窗口部件、布局管理、 文本、容器、目录和文件处理、事件机制、二维图形、MDI 程序设计、模型/视图结构、网 络编程、数据库、多线程、Qt4.5 移植等部分,详细介绍了 Qt 的基础知识和 GUI 编程应用。 同时在各个章节穿插了应用实例,使读者更容易上手掌握。 本书内容全面,体系完整,是广大读者不错的选择。可作为刚接触 Qt 的初学者进行查 阅学习,也适合已经在工作中应用的程序员和在从事 Qt 开发的科研人员参考翻阅,还可以 作为各大中专院校和培训机构的教材。 丛书编委会 主 编:奚海蛟 副主编:韩少云 编委会成员 李政春 杨桂浩 沈志豪 柴萌 郑超 刘张辉 陈璐璐 丁宏伟 刘星 目录 第一章 认识 Qt.................................................................................................................................1 1.1 Qt 介绍.................................................................................................................................... 1 1.1.1 Qt 扩展 C++..................................................................................................................... 1 1.1.2 Qt 模块............................................................................................................................. 2 1.1.3 Qt 授权模式.................................................................................................................... 4 1.1.4 Qt 特征............................................................................................................................ 4 1.1.5 不同平台的 Qt 简介....................................................................................................... 5 1.2 Qt 安装.................................................................................................................................... 6 1.3 建立 Qt 交叉编译环境........................................................................................................... 8 1.3.1 交叉编译器..................................................................................................................... 8 1.3.2 Qt embedded for arm 的安装............................................................................................ 8 1.4 Qt 工具介绍............................................................................................................................ 9 1.5 编写 Hello Qt 程序.............................................................................................................. 10 本章小结..................................................................................................................................... 11 第二章 信号与槽........................................................................................................................... 12 2.1 理解信号与槽...................................................................................................................... 12 2.2 预定义的信号与槽实例...................................................................................................... 13 2.3 创建和使用用户信号与槽.................................................................................................. 20 本章小结..................................................................................................................................... 34 第三章 对话框设计....................................................................................................................... 35 3.1 QDialog 类........................................................................................................................... 35 3.2 QDialog 类中派生类............................................................................................................ 36 3.2.1 QDialog 类中的派生类.................................................................................................. 36 3.2.2 派生类的实现............................................................................................................... 38 3.2.3 添加函数入口............................................................................................................... 39 3.3 使用 QtCreator..................................................................................................................... 41 3.3.1 创建工程....................................................................................................................... 41 3.3.2 编辑工程....................................................................................................................... 44 3.4 其它对话框类使用实例....................................................................................................... 46 3.4.1 常用的内建对话框........................................................................................................ 46 3.4.2 Qt 消息框....................................................................................................................... 54 本章小结..................................................................................................................................... 63 第四章 创建主窗口....................................................................................................................... 65 4.1 QMainWindow 类................................................................................................................. 65 4.2 创建窗口的方法和流程....................................................................................................... 66 4.3 代码创建主窗口.................................................................................................................. 67 4.3.1 头文件........................................................................................................................... 67 4.3.2 实现文件....................................................................................................................... 70 本章小结..................................................................................................................................... 85 第五章 自定义窗口部件............................................................................................................... 86 5.1 QWidget 类............................................................................................................................86 5.2 从 QWidget 中派生...............................................................................................................89 5.3 双缓冲技术........................................................................................................................... 99 本章小结................................................................................................................................... 107 第六章 部件布局......................................................................................................................... 108 6.1 Qt 布局管理器.................................................................................................................... 108 6.2 Qt 分裂器部件 QSplitter.....................................................................................................113 6.3 栈部件 QStackedWidget.................................................................................................... 115 6.4 工作空间 QWorkSpace...................................................................................................... 117 6.5 综合应用实例.................................................................................................................... 121 本章小结................................................................................................................................... 133 第七章 文本输入和表................................................................................................................. 135 7.1 文本输入类......................................................................................................................... 135 7.2 子类化 QTableWidget 及使用实例................................................................................... 142 7.3 QTableWidgetItem 的子类化..............................................................................................145 本章小结................................................................................................................................... 154 第八章 容器类............................................................................................................................. 155 8.1 Qt 容器类............................................................................................................................ 155 8.2 使用 QVector、QLinkList 和 QList 类............................................................................. 155 8.2.1 QVector 类.................................................................................................................... 155 8.2.2 QLinkedList 类............................................................................................................. 158 8.2.3 QList 类........................................................................................................................ 158 8.2.4 迭代器......................................................................................................................... 158 8.3 使用 QMap 和 QHash 类................................................................................................... 161 8.4 使用 QString、QByteArray、QVariant 及其它相关类。............................................... 164 8.5 隐式共享............................................................................................................................. 166 本章小结................................................................................................................................... 167 第九章 目录与文件处理............................................................................................................. 169 9.1 Qt 的目录操作类与实例.................................................................................................... 169 9.2 Qt 二进制文件数据读写.................................................................................................... 177 9.3 Qt 文本文件数据读写........................................................................................................ 179 本章小结................................................................................................................................... 182 第十章 Qt 中的事件机制............................................................................................................. 183 10.1 事件的起源...................................................................................................................... 183 10.2 事件的分类与处理.......................................................................................................... 183 10.3 事件过滤器...................................................................................................................... 193 10.4 时间事件.......................................................................................................................... 198 10.5 在强烈的处理中保持响应.............................................................................................. 201 本章小结................................................................................................................................... 202 第十一章 二维图形的绘制......................................................................................................... 203 11.1 QPainter 类介绍和绘图实例............................................................................................ 203 11.2 图像的装载和保存........................................................................................................... 223 11.2.1 图像的装载................................................................................................................ 223 11.2.2 图像的保存................................................................................................................ 223 11.3 坐标系统介绍和变换....................................................................................................... 224 11.3.1 坐标系统的介绍........................................................................................................ 224 11.3.2 坐标变换.................................................................................................................... 224 11.4 QPainter 的转换函数........................................................................................................ 225 11.5 QImage 类介绍和绘图实例..............................................................................................227 11.6 用 Qt 打印图形................................................................................................................. 230 本章小结................................................................................................................................... 234 第十二章 MDI 程序设计............................................................................................................. 235 12.1 MDI 的实现类.................................................................................................................. 235 12.2 一个 MDI 程序实现实例................................................................................................ 236 12.2.1 实现 MdiChild 中央窗口的子窗口........................................................................... 237 12.2.2 实现 MDI 程序的主窗口界面................................................................................... 241 12.2.3 实现功能函数............................................................................................................ 243 本章小结................................................................................................................................... 250 第十三章 Model/View 结构.......................................................................................................... 251 13.1 Model/View 结构介绍...................................................................................................... 251 13.2 Model 类............................................................................................................................252 13.3 创建新的 Model................................................................................................................257 13.4 View 类..............................................................................................................................264 13.5 Delegate 类........................................................................................................................ 265 本章小结................................................................................................................................... 268 第十四章 Qt 的网络编程............................................................................................................ 269 14.1 QFtp 类和程序设计实例.................................................................................................. 269 14.2 QHttp 类和程序设计实例................................................................................................ 275 14.3 TCP/IP 程序设计.............................................................................................................. 285 本章小结................................................................................................................................... 295 第十五章 数据库程序设计......................................................................................................... 296 15.1 数据库技术介绍.............................................................................................................. 296 15.2 Qt 的数据库操作.............................................................................................................. 301 15.2.1 连接数据库............................................................................................................... 301 15.2.2 常用数据库操作....................................................................................................... 302 15.2.3 事务操作................................................................................................................... 304 15.2.4 使用 SQL 模型类...................................................................................................... 305 15.3 一个数据库编程实例....................................................................................................... 306 本章小结................................................................................................................................... 312 第十六章 Qt 多线程程序设计................................................................................................. 314 16.1 多线程介绍.................................................................................................................. 314 16.2 Qt 中的线程创建和同步.................................................................................................. 315 16.3 线程间的同步与互斥机制.......................................................................................... 320 16.3.1 Semaphone 类的例子........................................................................................... 320 16.3.2 QWaitCondition 类的例子................................................................................... 323 16.4 优先级控制.................................................................................................................. 326 16.5 死锁问题...................................................................................................................... 327 本章小结................................................................................................................................... 327 第十七章 Qt4.5 在 S3C2440 上的移植和程序的调试和发布....................................................328 17.1 Qt/Embedded 的编译........................................................................................................ 328 17.1.1 安装交叉编译环境................................................................................................... 328 17.1.2 安装 Qt/Embedded.................................................................................................... 329 17.2 Qt4.5 移植到 S3C2440 开发板上.................................................................................... 329 17.3 QT 程序的调试技术......................................................................................................... 330 17.4 QT 应用程序的编译......................................................................................................... 332 17.4.1 配置 Qt Creator 交叉编译环境..................................................................................332 17.4.2 终端交叉编译............................................................................................................ 333 本章小结................................................................................................................................... 333 参考文献....................................................................................................................................... 334 第一章 认识 Qt Qt 是一个跨平台的 C++图形用户界面应用程序框架。它提供应用程序开发者建立图形 用户界面所需的功能。本章首先会从几个不同的方面介绍 Qt 的一些特性,然后会讲解在不 同的平台上 Qt 的安装。针对于不同的安装包,以及不同的参数配置会编译出 Qt 中的工具, 并会介绍 Qt 中经常使用到的工具。在建立好 Qt 环境之后,还要建立基于 arm 开发板的交叉 编译环境,为以后的应用程序可以移植到 arm 板上做准备。最后以一个简单的例子来了解一 下 Qt 程序的编写及编译过程。 本章要点:  Qt 介绍  Qt 安装  建立 Qt 交叉编译环境  Qt 工具介绍  编写 Hello Qt 程序 1.1 Qt 介绍 相对于需要记忆很多繁琐命令才可以运行的应用程序,更愿意使用具有人机交互的界 面,这样可以通过窗口、菜单、按键等方式来简便对软件进行操作。而构造图形用户程序要 用到 GUI(Graphical User Interface)工具包。该工具包是构造图形用户界面所使用的一套按 钮、滚动条、菜单和其他对象的集合。GUI 工具包也叫 GUI 库,库中提供做好构造图形界 面的小元件,利用这些小元件构造出合适的应用程序界面。 在 linux 系统中,有很多可供选择的 GUI 库,其中 Qt 是比较流行的一个。Qt 是一个完 整的 C++应用程序开发框架。从宏观上来看,Qt 就是用 C++写的一些类库。要用类库创建 界面,需要实例化相应的类构造出窗口部件,由窗口部件构建界面。 1.1.1 Qt 扩展 C++ C++的对象模型为面向对象的编程提供了非常高效的实时支持,但是在一些特定的领 域,它的静态性表现的不够灵活。而在 GUI 应用程序的编程领域,对实时性和灵活性都有 很高的要求。Qt 在 C++对象模型的基础之上,增加了一些特性,在保持 C++执行速度的同 时提供了所需要的灵活性。如果只使用 C++就可以完成所有的功能,就不需要 Qt 了。 Qt 相对于 C++主要增加了以下功能:  用于对象之间通信的信号与槽机制;  可以查询和设计对象的属性(Qt designer 中经常使用);  增加的事件处理系统和事件过滤器;  国际化支持,Qt 提供相应的转换函数,可以通过相应的映射表,将界面中所显示 一些字符转换为不同的语言;  支持多任务的定时器;  以树的形式组织对象,支持分层检索的对象树;  受保护的指针,当对象被销毁时,指向对象的指针会被自动置为零,而在 C++中, 1 当对象被销毁后,如果没有手动的置指向对象的指针为 0,该指针会成为野指针;  支持动态的类型装换; Qt 中扩展了 C++的一些功能主要通过 Qt 中的元对象系统来实现。元对象系统提供了两 项关键的技术:信号与槽、内省。 下面了解一下元对象系统所提供的两项关键技术:信号与槽机制,内省。 图 1-1 信号与槽 1.信号与槽 上图 1-1 显示的是用 Qt 编写的一个窗口,窗口中只有一个按钮。当单击按钮时,会产 生关闭窗口的结果。这个就是 Qt 中的信号与槽机制。A 对象发 M 信号给 B 对象,B 对象产 生 N 动作。在这个例子中,按钮就是 A 对象,所发送的 M 信号是单击按钮的信号,把信号 发送给当前的窗口 C,C 产生动作 N 关闭窗口。这是信号与槽最简单的用法。有关于它们 的用法将会在后面的章节里详细介绍。 2.内省 内省是指面向对象的编程语言在程序的运行期间查询对象信息的能力。在 C++中,存在 RTTI(运行时类型识别),也就是会根据运行时指针所指向的对象的类型判断要调用哪个类 中的函数,而不是根据指针的类型判断。C++中的内省只可以获取对象的类型信息,Qt 中的 内省允许应用程序在运行时获得有关调用的 QObject(Qt 中对象类的祖先类)子类的信息, 这个信息叫做“元信息”,其中包括一个含有对象的类名以及它所支持的信号与槽的列表。 将这些 C++中没有的功能转换为 C++编译器可以编译的代码,而信号与槽机制以及其 他的一些功能 C++中是没有的,需要元对象编辑器 moc(meta object compiler)。 元对象系统工作需要三部分:Q_OBJECT 宏、QObject 类、moc。这种机制的工作流程 是,在定义 QObject 子类时,用 Q_OBJECT 宏声明每个 QObject 子类中必须实现的内省函 数,这些函数是 QObject、QMetaObject 类中的一些虚函数。在编译时 moc 工具生成了用于 Q_OBJECT 声明的所有函数和所有信号的实现。将程序转换为 C++代码。 要注意的是,当定义 QObject 子类时,如果类的定义中包含了信号的定义或者是槽函数 的定义,类的定义文件,与类的实现文件一定要分成两个文件。即定义一个类时有两个文件, 以.h 结尾和以.cpp 结尾。 1.1.2 Qt 模块 Qt 中拥有完善的 C++图形库,还集成了数据库、OpenGL 库、多媒体库、网络、脚本库、 XML 库、WebKit 库等,其核心库也加入了进程间通信、多线程等模块。这些加入的模块极 大的丰富了 Qt 开发大规模跨平台应用程序的能力,也实现了其研发宗旨“Code Less Create More Deploy Anywhere”。 Qt 库不断完善,实现了不同的功能。其中主要分为以下几类:基础的实现、与用户界 面设计有关的部分、Qt 中与其他技术相结合连接的部分。 基础部分主要包括:Qt 的对象模型(the Qt Object model)、事件系统(event system)、线 程(threading)、国际化(internationalization)针对于特定平台的开发(platform specific)。 2 用户界面的设计既可以使用 Qt Designer,也可以使用代码。用户界面设计主要包括: 窗口和布局(widgets and layouts)、应用程序窗口设计(application windows )、绘图和打 印(painting and printing)、图形视图中的 canvas(canvas UI with Graphics View)、整合 web 的内容(integrating web content)。 还有一部分与技术有关:输入输出和资源(input/output and resources)、网络程序(network programming)、数据库开发(SQL Development)、XML 程序(XML processing)、脚本语言 (Scripting)。 这些不同部分的功能由 Qt 中的不同模块实现,主要包括以下模块: 图 1-2 Qt4.3 模块 上图 1-2 显示了 Qt4.3 中的模块,现在 Qt 的版本为 4.8,在 4.3 的基础上丰富了 Qt 模块, 各个模块的介绍如下:  QtCore 模块:所有基于 Qt 的应用程序的基础,提供信号与槽的对象间通信机制、 IO、事件和对象处理、多线程。  QtGui 模块:包含了开发图形用户界面应用程序所需的功能。使用其支持的各个平 台的原生图形 API。支持反锯齿、矢量形变。支持 ARGB 顶层 widget。  QtNetwork 模块:提供了网络程序设计功能。支持通用协定,如 HTTP、FTP 和 DNS, 包括对异步 HTTP1.1 的支持。  QtOpenGL 模块:提供在应用程序中使用 OpenGL 和 OpenGL ES 加入 3D 图形。在 Windows 平台上亦支持 Direct3D。  QtScript 模块:包含完全集成的 ECMA 标准脚本引擎。提供信号与槽机制简化对象 间通信和 QtScript 调试器。  QtSql 模块:将数据库集成至应用程序。支持所有主要的数据库驱动包括 ODBC、 MySQL、PSQL、SQLite、ibase、Oracle、Sybase、DB2。  QtSvg 模块:支持 SVG 格式  QtWebKit 模块:集成 WebKit,提供了 HTML 浏览器引擎,便于在原生应用程序中 嵌入网络内容和服务。  QtXml 模块:提供了 XML 文档的阅读器和编写器、支持 SAX 和 DOM。  QtXmlPatternsl 模块:提供了 XQuery 和 XPath 引擎支持。  Phonon 模块:集成 Phonon,支持跨平台应用程序播放音频和视频内容。  Qt3Support 模块:提供兼容 Qt 3.х.х版本的程序库 3  QtDesigner 模块:提供扩充 Qt Designer 的类型。  QtHelp 模块:协助集成联机文件到应用程序中。  QtTest 模块:提供单元测试框架和鼠标和键盘模拟功能。集成 Visual Studio 和 KDevelop。  QtMultimedia 模块:提供对 Qt 多媒体的支持。  QtOpenVG 模块:提供 OpenVG 绘图支持的一个插件  QtScriptTools 模块:额外的 Qt Script 组件 随着版本的升级,Qt 中所支持的功能越来越完善,在每个模块之下,是与此模块功能 相关的一些类库,这些类库具有继承的关系,如下图所示为类库中的一部分: 图 1-3 Qt 中类的继承关系 Qt 中通过模块化分大的功能,各个不同的模块又通过一系列的类来实现具体功能。这 些子类通过继承关系发生联系。需要学习的就是构成大网络的每个小的库。以后每章会分门 别类的讲解不同的类。 1.1.3 Qt 授权模式 Qt 开放源码,并且提供自由软件的用户协议。使得它可以被广泛地应用在各平台上的 开放源代码软件开发中。 Qt 提供三种授权方式。这三种方式提供同样的功能和性能,只是所用的授权协议不同。 LGPL 和 GPL 是免费发布,商业版则需要收取授权费。  Qt 商业版:适用于开发专属软件或者是商业软件。这个版本适用于利用 Qt 所创建 的应用程序不希望与他人共享源代码。需要支付一定的授权费。  GNU LGPL v.2.1-Qt4.5.0 及以后的版本开始遵循 GNU LGPL。LGPL 允许链接到它 的软件使用任意的许可证,可以被专属软件作为类库引用、发布和销售。  GNU GPL v.3.0 如果你希望将 Qt 应用程序与受 GNU 通用公共许可证(GPL)3.0 版本一同使用,或者你希望遵循该 GUN 许可证版本的条款,则适合使用这种授权 模式的 Qt。 1.1.4 Qt 特征 Qt 公司的两位创始人 Haavard Nord 和 Eirik Chambe-Eng 于 1991 年开始开发"Qt",1994 4 年 3 月 4 日创立公司,公司最早取名为 Quasar Technologies,然后更名为 TrollTech,然后再 改为 Trolltech,中文名是“奇趣科技”,2008 年 6 月 17 日被 NOKIA 公司收购,以增强该公 司跨平台方向研发方面的实力,更名为 Qt Software。现在的 Qt 的发展成为了一个更为开放, 功能更丰富,支持更多平台的图形界面开放工具。 2009 年诺基亚 Qt Software 宣布 Qt 源代码管理系统面向公众开放,Qt 开发人员可通过 为 Qt 以及与 Qt 相关的项目贡献代码、翻译、示例以及其他内容,协助引导和塑造 Qt 未来 的发展。为了便于这些内容的管理,Qt Software 启用了基于 Git 和 Gitorious 开源项目的 Web 源代码管理系统。 在推出开放式 Qt 代码库的同时,Qt Software 在其网站发布了其产品规划(Roadmap)。 其中概述了研发项目中的最新功能,展现了现阶段对 Qt 未来发展方向的观点,以期鼓励社 区提供反馈和贡献代码,共同引导和塑造 Qt 的未来。 Qt 是一种非常优秀的编程工具,具有很多优点和一些编程工具所不具备的特征。其中 最主要的特征主要归结为以下两点:  Qt 是一个完整的 C++应用程序开发框架,具有 C++的优点。在 C++的基础之上, 基于面向对象的编程思想,扩展了一些 Qt 中特有的类。  Qt 所提供的 API 在所有的平台上都是相同的,针对每一种 OS 平台,QT 都有一套 对应的底层类库,而接口是完全一致的。所以,Qt 工具在所有平台上的使用方式一致,因 而在 Qt 库上开发的程序,在任何平台上都可以编译运行(前提是程序中没有使用某系统的 特有功能)。轻松实现了“一次编写,随处编译”。 1.1.5 不同平台的 Qt 简介 对于不同的平台,Qt 提供不同的图形界面库,如:Qt/X11, Qt Windows, Qt Mac 等。由 于 Qt 最早是在 linux 中随着 KDE 流行开来的,因此,通常所说的 Qt 都是指用于 linux/unix 的 Qt/X11。 Qt/Embeded 是用于嵌入式 linux 系统的 Qt 版本,简称 Qte,相对于 linux 版本的 Qt,它 去掉了 X Lib 的依赖而直接工作在 Framebuffer 上,它并不是 Qt/X11 的子集,它有部分机制 就不能用于 Qt/X11 中。总之,它为嵌入式系统的开发人员搭建了一套完善的窗口系统和开 发平台。除了对嵌入式 linux 平台的支持,Qt 还增加了对 Windows CE,Symbian, Maemo5 等嵌入式平台的支持。 Qtopia 是一个面向嵌入式 Linux 的全方位应用程序开发平台,同时也是用于基于 Linux 的 PDA(个人数字助理),智能电话(Smartphone)以及其他移动设备的用户界面。简单地 说,Qtopia 实质上是一组关于 PDA 和智能电话的应用程序结合,如果需要开发这类产品可 以在这组程序的基础上迅速构建出 PDA 或者智能电话。Qtopia 实质上依赖 Qt/Embedded。 以下是在不同的平台上所用到的 Qt 版本:  Linux/X11:用于 X Window System(如 Solaris、AIX、HP-UX、Linux、BSD)。支 持 KDevelop 和 Eclipse IDE 集成。  Mac:用于 Apple Mac OS X。基于 Cocoa 框架。支持 Universal Binary。支持以 Xcode 编辑、编译和测试。  Windows:用于 Microsoft Windows。支持 Visual Studio 集成。  Embedded Linux:用于嵌入式 Linux。可以通过编译移除不常使用的组件与功能。 通过自己的视窗系统 QWS,不需依赖 X Window System,直接写入 Linux 帧缓冲。 可以减少存储器消耗。并提供虚拟帧缓冲 QVFb,方便在桌面系统上进行嵌入式测 5 试。  Windows CE / Mobile :用于 Windows CE。  Symbian:用于 Symbian platform。  Maemo/MeeGo:用于 Maemo。  Wayland –用于 Wayland 显示服务器,Qt 应用程序可以在运行时切换图形后端,如 X 与 Wayland。 1.2 Qt 安装 Qt 具有跨平台性,支持多种平台。在本书中开发 Qt 程序要用到两种开发环境,一种是 在 Linux 中安装 Qt,用于在计算机上开发 Qt 应用程序,另外一种是在 Linux 中安装 Qt for embedded Linux,这是个 Qt 开发环境要编译可以在 arm 开发板上运行的程序。 Qt 程序的安装包都可以在其官网上免费获取(http://www.trolltech.com)。既可以下载 Qt 的 SDK 包,也可以下载 Qt 库。 Qt 的 SDK 包中包含有 Qt 包、Qt Creator IDE 和 Qt development,安装 Qt 的 SDK 包与 正常的 Linux 系统中安装图形应用程序一样,直接将程序运行之后单击下一步到结束就可以 了,最后在系统的配置文件中配置相应的环境变量(与安装库时环境变量的配置方法相同)。 SDK 包所打包的文件是二进制包,安装过程比较简单,也比较快。建议大家安装 Qt 的 SDK 版本。安装 SDK 包的主要步骤: (1)下载 Qt_SDK_Lin32_offline_v1_1_3_en.run; (2)赋予可执行权限 chmod 755 Qt_SDK_Lin32_offline_v1_1_3_en.run; (3)运行./ Qt_SDK_Lin32_offline_v1_1_3_en.run; (4)安装完成之后,安装相应的字体库和设置相应的环境变量(下一种方法会详细的 讲解)。 也可以从 Qt 的源码包开始安装。下面介绍怎样从下载好的源代码库编译出所需要的 Qt 工具以及库文件。在下载 Qt 库时在 nokia 的 ftp 服务器上直接下载(ftp://ftp.qt.nokia.com), 其中库文件在所打开目录的 qt/source/下。下载需要的源文件。 这里安装的是 qt-everywhere-opensource-src-4.7.4.tar.gz。在安装 Qt/X11 之前需要保证你 的 linux 系统下已经安装了 gcc,make 等编译工具,以及 Xlib 相关的库等。 安装步骤如下: (1)如果要安装 Qt 的商业版本,首先要安装相应的 license。安装的是开源版本,所以 不用安装 license,这里可以跳过第一步; (2)将压缩包下载到某个路径下(/usr),解压文件: tar xzvf qt-everywhere-opensource-src-4.7.4.tar.gz (3)将目录切换至解压好的文件下: cd qt-everywhere-opensource-src-4.7.4 (4)运行文件夹下的./configure,生成配置文件。如果不加任何参数的话会生成系统的 默认配置文件,也可以根据需要添加所需的参数。 参数可以通过./configure -help 查看,经常使用到的参数有:  -prefix 如果不指定安装目录时,默认情况会安装到/usr/local/Trolltech/Qt-4.7.4 目录下。当想要改变 Qt 的安装目录时,用参数-prefix 后面加上想要安装的目录。  -release 这个选项指定编译 Qt 程序时系统不会做出优化,在开发过城中经常使用 此选项,是系统的默认选项。  -debug 这个选项指定编译 Qt 程序时会对程序进行优化,在编译要最后发布的软件 6 的时候,要用到这个选项。  -opensource 指定编译开源版本发布程序,当然还有可以指定编译商业版的参数, 如果不指定,在生成配置文件的时候,会让选择到底安装哪个版本。 Qt 的配置文件生成之后,会根据所选定的配置选项来生成相应的 Makefile 文件直接 make,根据配置文件编译源代码。这样将会生成 Qt 库,同时也会编译所有源代码中所带的 演示程序、示例程序和工具软件。编译源代码所需要的时间比较长,大概等两个小时。 升级系统中的 fontconfig 库。系统中安装的字体库版本太低,会导致编译出错,下载最 新版本的字体库,安装之后就不会出错。 系统中 fontconfig 版本太低,在编译时会有错误提示: 图 1-4 错误显示 解决的办法是: (1)下载 fontconfig-2.8.0.tar.gz 或更高版本的 fontconfig 库,下载地址 http://fontconfig.org/release/fontconfig-2.8.0.tar.gz ; (2)解压缩 fontconfig-2.8.0.tar.gz 文件: tar xvzf fontconfig-2.8.0.tar.gz (3)进入 fontconfig 库顶层目录: cd fontconfig-2.8.0 (4)进行配置,以生成 Makefile 文件: ./configure --sysconfdir=/etc --prefix=/usr --mandir=/usr/share/man (5)编译 fontconfig 库: make (6)安装 fontconfig 库,完成字体库的升级: make install 安装 Qt,输入命令:make install。如果安装的时候没有权限,切换为 root 用户,或 sudo make install。当使用./configure 生成 Makefile 时,如果没有指定要安装的路径,Qt 默认 是安装到/usr/local/Trolltech/Qt-4.7.4 目录中。想改变安装路径,那么可以在 configure 命令的 后面使用 -prefix 选项来做到这一点。 设置 PATH。前面已经大致完成了安装 Qt 的工作,为了在平时 Qt 开发中能更方便的使 用 Qt 提供的 qmake,moc 等工具,把 Qt 的安装路径添加到 PATH 变量里。 设置环境变量 PATH 时要修改相应的配置文件,在 Linux 操作系统中可以修改的配置文 件主要有以下几个:  /etc/profile 全局的配置,适用于所有的 shell,profile 文件会告诉 shell 使用什么语 言,什么 shell,命令的搜索路径等。修改后要重启机器生效。  /etc/bash.bashrc 所有用户公用的配置,shell 脚本,适用于 bash,其他类型的 shell 有相对应的配置文件。(不同的系统,可能配置文件的名字不同,给出的名字是 ubuntu 中的配置文件的名字。)  ~/.bash_profile 该文件在当前用户的主目录下,每个用户有自己特定的配置。修 改后,重新登录即可生效。  ~/.bashrc 跟 bash_profile 类似,并且被这个文件调用,区别是.bashrc 可以在非登录 模式下生效。 其中,修改全局的配置文件,发生错误的话,会导致其他用户也出错。所以,最好修改 用户自己相应的配置文件。修改方法都相同。 7 (1)用 vi 编辑器打开~/.bash_profile,在文件中添加: PATH=/usr/local/Qt-4.7.4/bin:$PATH export PATH (2)修改完成后保存文件,然后用 source 命令重新运行修改的脚本,使设置生效。 source ~/bash_profile (4)这时候再运行 echo $PATH 可以看到 PATH 中已经加入了 qmake ,moc 等工具的路径。如果没有显示新加入的路径, 查看添加的路径是否正确,然后重新应用配置文件。或者重新启动系统。 图 1-5 路径显示 Qt 安装完成后,可以打开 Qt 中的演示程序,充分体验 Qt 库的特色。要查看 Qt 的文档, 既可以访问 Qt 的网站,也可以运行 Qt 助手。Qt 助手是 Qt 的一个帮助程序,只需在控制台 窗口中输入 assitant 命令即可把它调出来。 1.3 建立 Qt 交叉编译环境 Qt 的不同版本,适用于不同的平台,如果要编译的软件不是运行在 PC 机上,而是要显 示在手机,PDA 等一些嵌入式设备中,就不能再用 PC 上的 Qt 开发工具包,而要用到 Qt for Embedded Linux。 Qt for Embedded Linux 支持三种体系结构,x86、arm、mips。在这里要安装的是 for arm 体系结构的版本。 1.3.1 交叉编译器 嵌入式系统中应用程序的开发有别于普通的 PC 程序的开发,主要表现在程序的编辑、 编译和程序的运行不在同一台设备上,通常前者在开发机(PC)上,后者在嵌入式设备(ARM 开发板)上。这样就要求在进行实际开发前必须要搭建基于 arm 的嵌入式 Linux 交叉编译环 境。 编译能够运行在 arm 上的可执行程序,要用到 arm-linux-g++交叉编译器。arm 体系结构 上用到的指令集是 arm 指令集,PC 上所用到的指令集是 X86 指令集。要在 PC 机上编译出 最后能够在 arm 上运行的应用程序,所用到的编译器叫做交叉编译器。即编译器运行于一种 体系结构上,生成能够在另一种体系结构上执行的代码。 交叉编译器即可以通过下载相应的制作工具以及适用于 linux PC 平台的 gcc 工具包自己 制作,也可以下载别人已经编译好的工具包。总之在安装 Qt Embedded for arm 之前,要将 交叉编译器安装好(交叉编译器的版本不能太低,否则在编译 Qt 的时候会出错,这里所用 的是 arm-linux-gcc 4.4.3.tar.gz)。交叉编译器是已经编译好的二进制包,只需要解压到某个 路径,再将这个路径加入到环境变量中,环境变量的添加与在 Qt 安装时添加环境变量方法 相同。 1.3.2 Qt embedded for arm 的安装 底层编译器安装好以后,要安装相应的 Qt for Embedded Linux;通过相应的配置选项编 8 译成 arm 版。对于 for arm 的 Qt 安装,首先要在 Nokia 的官方网站上下载相应的 Linux 安装 包(安装包在 Nokia 的 ftp 服务器下载): qt-embedded-linux-opensource-src-4.5.3.tar.gz 源代码包下载好了之后,首先将下载的源代码包解压缩。要生成可以编译成在 arm 体系 结构上运行的 Qt 程序,可以通过两种方法,一种是通过运行配置好的脚本文件。另外一种 通过配置选项配置符合的 Qt。这里使用第二种方法,编译一个运行在 pc 机上的 Qt,这个 Qt 编译出来的程序可以运行在 arm 上。安装步骤如下: (1)解压缩之后,运行 ./configure 生成 Makefile 文件。 生成 Makefile 文件时要加相应的参数。 -embedded arm,指定 Qt 的硬件架构为 arm。 -prefix 参数, 指定要安装的路径。(如果不指定会有默认的安装路径,同 linux 平台的 Qt 安装。) 例:-prefix /usr/local/Qt 如果在配置的过程中出错,可以在配置时使用-v 选项来查看出错原因。 例:./configure embedded arm - qvbf -v 如果想要在第一次配置的基础上改变配置选项,要运行“make confclean”清除之前的 配置。其余的参数可以通过./configure -help 获取。 (2)配置成功后,输入“make”即可编译。 (3)编译完成后,直接输入“make install”将 Qt 安装到指定的目录中。 在安装完成以后,以后要用到 for arm 的 Qt 编译器,编译 Qt 工程文件的时候,要用到 的 qmake 工具是 for arm 的,直接输入全路径编译。 例如: 编译 for PC 的 Qt 过程是: (1)qmake -project(qmake 命令,用于创建 hello.pro,将所有的文件编译成一个与平 台无关的工程文件。) (2)qmake (qmake 命令,读取本身的 Qt 设置,生成与库一致的相应的 Makefile。) (3)make(根据生成的 Makefile,将文件编译为二进制可执行程序。) 编译 for arm 的 Qt 过程为: (1) /usr/local/Qt/bin/qmake –project (2) /usr/local/Qt/bin/qmake (3) make 1.4 Qt 工具介绍 Qt/X11 安装完成,切换到 Qt 的安装目录,查看 bin 目录,其中显示的就是 Qt 中提供的 工具,如下图 1-6 所示: 图 1-6 Qt 工具  assistant:Qt 提供强大的帮助文档,如果安装的是 Qt 的 SDK 包,可以直接通过打 开 Qt creater 打开 Qt 的帮助文档。也可以在命令行通过键入 assistant 打开帮助文档。 9  moc:元对象编译器,用于元对象系统。处理带有 Q_OBJECT 宏的头文件,生成 形如 moc_xxx.h,moc_xxx.cpp 的 C++代码,之后再与程序的代码一同编译。这个命 令行工具也不需要手动调用。  qmake:用于生成 Makefile 的命令行工具。它是 Qt 跨平台编译系统的基础。它的 主要特点是可以读取 Qt 本身的配置,为程序生成与库一致的 Makefile。编译文件 的时候,首先用 qmake 工具将源文件编译成一个工程文件 qmake -project ,然后再根 据所生成的工程文件,生成 Makefile。  rcc:在编译程序的时候,这个工具用于将 Qt 的资源文件嵌入到应用程序中。可以 直接处理.qrc 文件,将文件中的数据加入到可执行程序中,不用单独的加资源文件。  designer:用于设计窗口组件的应用程序,使用它可以很方便的制作应用程序界面, 可以用拖拽的方式将控件摆布在界面上,支持布局,支持信号和槽(Qt 中特有的, 后面会讲到)的编辑,可以得到 xxx.ui 的用户界面文件,该文件是按照 XML 格式 保存的  pixeltool:像素放大工具,鼠标滑过的地方会在弹出的窗口界面上显示放大的像素。  uic(UI Compiler):这个命令行工具是用来编译 ui 文件的,将由 designer 编辑的 xxx.ui 文件转换为 xxx.h 和 xxx.cpp 文件。这个工具通常情况下不需要用户去手动 调用,qmake 会帮你管理 ui 文件和调用 uic 工具。  linguist、lupdate、lrelease、lconvert,用于支持国际化的一些支持。  qt3to4:Qt4 提供对 Qt3 的兼容。  uic3:Qt4 中提供的处理 Qt3 ui 文件的工具,生成的代码是 Qt4 的代码,可以放在 Qt4 的工程里使用。需要注意的是,uic3 生成的代码有一部分会使用一些 Qt3 支持 的库的 API,并不是纯的 Qt4 代码。  qtconfig:X11 系统下用于配置 Qt 环境的工具。可以设定字体、风格等。所设置的 信息被保存在当前用户主目录中。  qtdemo:Qt 例子和演示程序的加载器。用户可以通过这个工具方便的查看 Qt 提供 的例子程序。 安装 SDK 包的时候,安装了 Qt Creater,它是用于编译 Qt 项目的 IDE 工具,相当于一 个简单化的 Qt 开发环境,是开发 Qt4 应用程序的利器。可以在其中编辑、编译程序,查看 运行结果。 1.5 编写 Hello Qt 程序 Qt 的环境搭建好以后,先从一个非常简单的 Qt 程序开始。首先地研究这个程序的每一 行,然后将会看到如何编译运行它。 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} 10 图 1-7 hello 程序运行结果 上图 1-7 显示的就是程序的运行结果,其中的代码解释如下: 第 1,2 行:程序中所需要的类的头文件。Qt 是 C++的应用程序开发框架,对于头文件 的包含与 C++相同。 第 3 行:main 函数的标准写法。 第 5 行:创建一个 QApplication 对象,管理应用程序的资源。 第 6 行:创建一个 QLable 对象。QLable 是一个小控件,这个小控件可以显示一行文本, 显示的文本内容是双引号中的内容。 第 7 行:上面图 1-7 只是创建了一个小控件,显示的是所创建的 QLable。 第 8 行:QApplication.exec()是让程序进入消息循环。等待可能的菜单,工具条,鼠标 等地输入,然后进行响应。 在 Qt 中最简单的程序就是利用已经存在的一些类,创建其对象,然后将它显示出来。 将以上代码放到名为 hello.cpp 中,保存在名为 hello 的文件夹中,编译过程如下: (1)qmake -project(qmake 命令,用于创建 hello.pro,将所有的文件编译成一个与平 台无关的工程文件。) (2)qmake (qmake 命令,读取本身的 Qt 设置,生成与库一致的相应的 Makefile。) (3)make(根据生成的 Makefile,将文件编译为二进制可执行程序。) Qt 程序的编译都要经过这三个步骤,当所编辑的程序出错时,除去语法错误,其余情 况下,大多数是因为找不到库或者是没有函数的定义,Qt 的版本中 4.5 版之前与之后的差别 比较大,库中的文件有很多不同,对于现在的 Qt 版本还有提供兼容 3.x.x 版本的模块。编译 出错改正之后,键入命令 make distclean 消除之前的编译操作。然后再用相应的命令重新编 译即可。 这样直接编译出来的程序可以在 PC 机上运行,所用到的 qmake 工具是安装在 X11 上 的。如果想要编译能够在 arm 开发板上运行的程序,需要使用适用于 arm 开发板的编译器, 首先切换到要编译的程序目录下,编译过程如下: (1)/usr/local/Qt/bin/qmake -project(qmake 命令,用于创建 pro 项目文件。) (2)/usr/local/Qt/bin/qmake(qmake 命令,编译生成与库一致的相应的 Makefile。) (3)make(根据生成的 Makefile 文件中的编译规则,将文件编译为可在 arm 开发板上 执行的二进制可执行文件。) 编译的时候可以看到底层的编译器调用的是 arm-linux-g++,而不是调用的 g++,编译出 来是适合于 arm 开发板的。 图 1-8 用 arm-linux 编译 编译过程没有出错,运行编译结果,会显示错误,不能在 PC 机上运行;PC 机是 X86 的结构,将程序移植到 arm 开发板上测试是否可以运行。 11 本章小结 本章主要介绍了 Qt 的相关概念,Qt 不同的版本,Qt 安装在不同的平台上。开发嵌入式 的 Qt 应用软件时,需要建立的交叉编译环境。最后一小节,通过 Hello Qt 的文本显示,简 单的了解了一下 Qt 的开发以及编译流程。 12 第二章 信号与槽 信号与槽是 Qt 中非常重要的机制,也是 Qt 中所特有的一种机制,几乎贯穿整个 Qt 的 学习过程中。 本章要点:  信号与槽的简介  预定义信号与槽  自定义信号与槽 2.1 理解信号与槽 在 GUI 用户界面中,当用户操作一个窗口部件时,需要其它窗口响应或者可以激活其 它的操作。在所熟知的很多 GUI 工具包中,窗口小部件 (widget) 都有一个回调函数用于响 应它们能触发的每个动作,这个回调函数通常是一个指向某个函数的指针。但是,在 Qt 中 信号与槽取代了这些凌乱的函数指针,使得编写这些通信程序更为简洁明了。 信号与槽机制是 Qt 的核心机制,要精通 Qt 编程就必须对信号与槽有所了解。信号与 槽是一种高级接口,应用于对象之间的通信;它是 Qt 的核心特性,也是 Qt 区别于其它工 具包的重要地方。信号与槽是 Qt 自行定义的一种通信机制,它独立于标准的 C/C++ 语言, 因此要正确的处理信号与槽,必须借助一个称为 moc(Meta Object Compiler)的 Qt 工具; 该工具是一个 C++ 预处理程序,它为高层次的事件处理自动生成所需要的附加代码。信号 与槽能携带任意数量和任意类型的参数,他们是完全安全的类型。 所有从 QObject 或其子类 ( 例如 Qwidget) 派生的类都能够包含信号与槽。当对象改 变其状态时,信号就由该对象发射 (emit) 出去,这就是对象所要做的全部事情,它并不知 道另一端是谁在接收这个信号。这个过程就是真正的信息封装,它确保对象是被当作一个真 正的软件组件来使用的。槽用于接收信号,但它们是普通的对象成员函数。一个槽并不知道 是否有任何信号与自己相连接,而且对象并不了解具体的通信机制。 可以将很多信号与单个的槽进行连接,也可以将单个的信号与很多的槽进行连接,甚至 于将一个信号与另外一个信号相连接也是可以的;这时无论第一个信号什么时候发射,系统 都将立刻发射第二个信号。总之,信号与槽构造了一个强大的部件编程机制。 信号与槽通过 QObject::connect( const QObject * sender,const char * signal, const QObject * receiver, const char * method, Qt::Connection type = Qt::AutoCompatConnection )函数关联, 参数 type 定义了信号与槽的关联方式,决定一个信号是立即传递到槽还是排队等待以后传 递。具体如图 2-1 所示: 13 图 2-1 信号与槽的关联方式 Qt::ConnectionType 定义信号和槽关联方式有三种:  Qt::DirectConnection:信号发送后立即传递给相关联的槽,只有槽函数执行完毕返 回后,发送信号“emit<信号>”之后的代码才被执行。  Qt::QueuedConnection:信号发送后排队,直到事件循环(event loop)有能力将它传 递给槽,而不管槽函数有没有执行,发送信号“emit<信号>”之后的代码都会立即 得到执行。  Qt::AutoCompatConnection:如果信号和槽在同一个线程,信号发出后槽函数立即 执行,等同于 Qt::DirectConnection;如果信号和槽不在同一线程,信号将排队,等 待事件循环的处理,效果等同于 Qt::QueuedConnection。 Qt 信号与槽机制的优点:  类型安全的 需要关联的信号与槽的参数类型和参数个数必须是等同的。不过一个槽的参数个数是可 以少于信号的参数个数的,但缺少的参数必须是信号的最后一个或几个。如果信号与槽参数 不符,编译器就会报错。  松散耦合的 Qt 信号和槽机制减弱了 Qt 对象的耦合度。当对象改变其状态时,信号就由该对象发射 (emit) 出去,这就是对象所要做的全部事情,它不知道另一端是谁在接收这个信号。这就是 真正的信息封装,它确保对象被当作一个真正的软件组件来使用。槽用于接收信号,但它们 是普通的对象成员函数。一个槽并不知道是否有任何信号与自己相连接。而且,对象并不了 解具体的通信机制。即使关联的对象在运行时被删除,应用程序也不会出现崩溃。 2.2 预定义的信号与槽实例 2.2.1 信号 当某个信号对其客户或所有者发生的内部状态发生改变,信号被一个对象发射。只有定 义过这个信号的类及其派生类能够发射这个信号。当一个信号被发射时,与其相关联的槽将 被立刻执行,就象一个正常的函数调用一样。信号与槽机制完全独立于任何 GUI 事件循环。 如果存在多个槽与某个信号相关联,那么当这个信号被发射时,这些槽将会一个接一个地 执 行;但是它们执行的顺序将会是随机的、不确定的,而且不能随意地指定哪个先执行、哪个 后执行。 14 信号的声明是在头文件中进行的,Qt 的 signals 关键字指出进入了信号声明区,随后即 可声明自己的信号。例如,下面定义了三个信号: signals: void mySignal(); void mySignal(int x); void mySignalParam(int x,int y); 在上面的定义中,signals 是 Qt 的关键字,而非 C/C++ 的。接下来的一行 void mySignal() 定义了信号 mySignal,这个信号没有携带参数;接下来的一行 void mySignal(int x) 定义了重名信号 mySignal,但是它携带一个整形参数,这有点类似于 C++ 中的函数重 载。从形式上讲信号的声明与普通的 C++ 函数是一样的,但是信号却没有函数体定义,另 外,信号的返回类型都是 void,不要指望能从信号返回什么有用信息。信号由 moc 自动产 生,它们不应该在 .cpp 文件中实现。 2.2.2 槽 槽是普通的 C++ 成员函数,可以被正常调用,它们唯一的特殊性就是很多信号可以与 其相关联。当与其关联的信号被发射时,这个槽就会被调用。槽可以有参数,但槽的参数不 能有缺省值。 既然槽是普通的成员函数,因此与其它的函数一样,它们也有权限。槽的权限决定了谁 能够与其相关联。同普通的 C++ 成员函数一样,槽函数也分为三种类型,即 public slots、 private slots 和 protected slots。  public slots:在这个区内声明的槽意味着任何对象都可将信号与之相连接。这对于 组件编程非常有用,可以创建彼此互不了解的对象,将它们的信号与槽进行连接以 便信息能够正确的传递。  protected slots:在这个区内声明的槽意味着当前类及其子类可以将信号与之相连 接。这适用于那些槽,它们是类实现的一部分,但是其界面接口却面向外部。  private slots:在这个区内声明的槽意味着只有类自己可以将信号与之相连接。这适 用于联系非常紧密的类。 槽也能够声明为虚函数,这也是非常有用的。 槽的声明也是在头文件中进行的。例如,下面声明了三个槽: public slots: void mySlot(); void mySlot(int x); void mySignalParam(int x,int y); 2.2.3 信号与槽的关联 通过调用 QObject 对象的 connect 函数来将某个对象的信号与另外一个对象的槽函数 相关联,这样当发射者发射信号时,接收者的槽函数将被调用。该函数的定义如下: bool QObject::connect ( const QObject * sender, const char * signal, const QObject * receiver, const char * member ) [static] 这个函数的作用就是将发射者 sender 对象中的信号 signal 与接收者 receiver 中的 member 槽函数联系起来。当指定信号 signal 时必须使用 Qt 的宏 SIGNAL(),当指定槽函 15 数时必须使用宏 SLOT()。如果发射者与接收者属于同一个对象的话,那么在 connect 调用 中接收者参数可以省略。 例如,下面定义了两个对象:标签对象 label 和滚动条对象 scroll,并将 valueChanged() 信号与标签对象的 setNum() 相关联,另外信号还携带了一个整形参数,这样标签总是显示 滚动条所处位置的值。 QLabel *label = new QLabel; QScrollBar *scroll = new QScrollBar; QObject::connect( scroll, SIGNAL(valueChanged(int)),label, SLOT(setNum(int))); 一个信号甚至能够与另一个信号相关联,看下面的例子: class MyWidget : public QWidget { public: MyWidget(); ... signals: void sig1(); ... private: ... QPushButton *Button1; }; MyWidget::MyWidget() { Button1 = new QPushButton( this ); connect( Button1, SIGNAL(clicked()), SIGNAL(Sig1()) ); } 在上面的构造函数中,MyWidget 创建了一个私有的按钮 Button1,按钮的单击事件产 生的信号 clicked()与另外一个信号 sig1()进行了关联。这样一来,当信号 clicked()被发射时, 信号 sig1()也接着被发射。当然,你也可以直接将单击事件与某个私有的槽函数相关联,然 后在槽中发射 sig1()信号。 当信号与槽没有必要继续保持关联时,可以使用 disconnect 函数来断开连接。其定义 如下: bool QObject::disconnect ( const QObject * sender, const char * signal, const Object * receiver, const char * member ) [static] 这个函数断开发射者中的信号与接收者中的槽函数之间的关联。 有三种情况必须使用 disconnect() 函数:  断开与某个对象相关联的任何对象。这似乎有点不可理解,事实上,当在某个对象 中定义了一个或者多个信号,这些信号与另外若干个对象中的槽相关联,如果要切断这些关 联的话,就可以利用这个方法,非常简洁。 例: disconnect( myObject, 0, 0, 0 ) 或者 myObject->disconnect()  断开与某个特定信号的任何关联。 16 例: disconnect( myObject, SIGNAL(mySignal()), 0, 0 ) 或者 myObject->disconnect( SIGNAL(mySignal()) )  断开两个对象之间的关联。 例: disconnect( myObject, 0, myReceiver, 0 ) 或者 myObject->disconnect( myReceiver ) 在 disconnect 函数中 0 可以用作一个通配符,分别表示任何信号、任何接收对象、接 收对象中的任何槽函数。但是发射者 sender 不能为 0,其它三个参数的值可以等于 0。 2.2.4 元对象工具 元对象编译器 moc(meta object compiler)对 C++ 文件中的类声明进行分析并产生用 于初始化元对象的 C++ 代码,元对象包含全部信号与槽的名字以及指向这些函数的指针。 moc 读 C++源文件,如果发现有 Q_OBJECT 宏声明的类,它就会生成另外一个 C++ 源文件,这个新生成的文件中包含有该类的元对象代码。例如,假设有一个头文件 sigtest.h, 在这个文件中包含有信号或槽的声明,那么在编译之前 moc 工具就会根据该文件自动生成 一个名为 sigtest_moc.h 的 C++ 源文件并将其提交给编译器;类似地,对应于 sigtest.cpp 文 件 moc 工具将自动生成一个名为 sigtest_moc.cpp 文件提交给编译器。 元对象代码是 signal/slot 机制所必须的。用 moc 产生的 C++ 源文件必须与类实现一 起进行编译和连接,或者用 #include 语句将其包含到类的源文件中。moc 并不扩展 #include 或者 #define 宏定义 , 它只是简单的跳过所遇到的任何预处理指令。在编译完之后也会产 生一个链接文件 sigtest_moc.o。 2.2.5 程序样例 这里给出了一个简单的样例程序,程序中定义了三个信号、三个槽函数,然后将信号与 槽进行了关联,每个槽函数只是简单的弹出一个对话框窗口。可以用 qtcreater 或者使用 vim 编辑器和 qmake 工具生成一个简单的 Qt 应用程序,然后将下面的代码添加到相应的程序中 去。 信号与槽函数的声明一般位于头文件中,同时在类声明开始位置必须加上 Q_OBJECT 语句;这条语句是不可缺少的,它将告诉编译器在编译之前必须先应用 moc 工具进行扩展。 关键字 signals 指出随后开始信号的声明, siganls 没有 public、private、protected 等属性, 这点不同于 slots。另外,signals、slots 关键字是 Qt 自己定义的,不是 C++ 中的关键字。 信号的声明类似于函数的声明而非变量的声明,左边要有类型,右边要有括号;如果要 向槽中传递参数的话,在括号中指定每个形式参数的类型。当然,形式参数的个数可以多于 一个。 关键字 slots 指出随后开始槽的声明。槽的声明与普通函数的声明一样,可以携带零或 多个形式参数。既然信号的声明类似于普通 C++ 函数的声明;那么,信号也可采用 C++ 中 虚函数的形式进行声明,即同名但参数不同。例如,第一次定义的 void mySignal() 没有带 参数,而第二次定义的却带有参数,从这里可以看到 Qt 的信号机制是非常灵活的。 17 信号与槽之间的联系必须事先用 connect 函数进行指定。如果要断开二者之间的联系, 可以使用函数 disconnect。 例如: //tsignal.h ... class TsignalApp:public QMainWindow { Q_OBJECT ... // 信号声明区 signals: void mySignal();// 声明信号 mySignal() void mySignal(int x); // 声明信号 mySignal(int) void mySignalParam(int x,int y); // 声明信号 mySignalParam(int,int) // 槽声明区 public slots: void mySlot();// 声明槽函数 mySlot() void mySlot(int x); // 声明槽函数 mySlot(int) void mySignalParam(int x,int y); // 声明槽函数 mySignalParam (int,int) } ... //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) { 18 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); } 2.2.6 应注意的问题 信号与槽机制是比较灵活的,但有些局限性必须了解,这样在实际的使用过程中做到有 的放矢,避免产生一些错误。下面就介绍一下这方面的情况。  信号与槽的效率是非常高的,但是同真正的回调函数比较起来,由于增加了灵活性, 因此在速度上还是有所损失;当然这种损失相对来说是比较小的,但如果要追求高 效率的话;比如在实时系统中,就要尽可能的少用这种机制。  信号与槽机制与普通函数的调用一样,如果使用不当的话,在程序执行时也有可能 产生死循环。因此,在定义槽函数时一定要注意避免间接形成无限循环,即在槽中 再次发射所接收到的同样信号。防止形成死循环。  如果一个信号与多个槽相联系的话,那么,当这个信号被发射时,与之相关的槽被 激活的顺序将是随机的。  宏定义不能用在 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 { 19 [...] signals: void someSignal( SIGNEDNESS(a) ); [...] };  构造函数不能用在 signals 或者 slots 声明区域内。的确,将一个构造函数放在 signals 或者 slots 区内有点不可理解,无论如何,不能将它们放在 private slots、 protected slots 或者 public slots 区内。下面的用法是不合语法要求的: class SomeClass : public QObject { Q_OBJECT public slots: SomeClass( QObject *parent, const char *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,在槽函数声明中使用 是错误的 }; 20  信号与槽也不能携带模板类参数。如果将信号、槽声明为模板类参数的话,即使 moc 工具不报告错误,也不可能得到预期的结果。例如,下面的例子中当信号发 射时,槽函数不会被正确调用: [...] public slots: void MyWidget::setLocation (pair location); [...] public signals: void MyObject::moved (pair location); 但是,可以使用 typedef 语句来绕过这个限制。如下所示: typedef pair IntPair; [...] public slots: void MyWidget::setLocation (IntPair location); [...] public signals: void MyObject::moved (IntPair location); 这样使用的话,就可以得到正确的结果。  嵌套的类不能位于信号或槽区域内,也不能有信号或者槽。 例如,下面的例子中,在 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 21 [...] signals: // 信号定义区 friend class ClassTemplate; // 此处定义不合语法 }; 2.3 创建和使用用户信号与槽 在这里看一个具体的实例,在日常生活中是很常见的计算器。 (1)看一下这个计算器的界面,如图 2-2: 图 2-2 计算器界面 这界面上有很多按键,实现了计算器的一些简单功能,以及一些科学计算器的功能。当 然,一个完整的 Qt 应用包括其它的一些知识;比如这个应用,布局也是其中的一个重点内 容,但是这里主要讲的就是有关信号与槽的应用,其它的内容在后面的章节会介绍。 其次,看一下一个 Qt 的应用中包括了哪些文件,这里使用 QtCreater 打开 calculator.pro (位于光盘:\第二章\code\calculator),如图 2-3: 如图 2-3 文件总览 其中 calculator.pro 是项目文件,button.h 和 calculator.h 是头文件,其它的三个以.cpp 结 尾的文件是源文件,主要是头文件里面一些函数实现。 22 (2)查看该项目文件 calculator.pro 的内容: HEADERS = button.h \ calculator.h SOURCES = button.cpp \ calculator.cpp \ main.cpp 该文件内包含了项目所涉及的所有的源文件,包括头文件和.cpp 文件,以及个别项目需 包含的特别文件,如库等。 (3)main.cpp 是整个文件的开始,这里面有整个程序的开始函数 main 主函数。 #include //Qt 程序必须包含的头文件 #include "calculator.h" int main(int argc, char *argv[]) { } QApplication app(argc, argv);//实例化一个应用 Calculator calc;//实例化计算器应用 calc.show();//显示图形界面 return app.exec();//等待应用退出 这是整个 Qt 程序开始的地方,这个已经是一个固定的格式了。 (3)头文件 calculator.h。 #ifndef CALCULATOR_H #define CALCULATOR_H #include QT_BEGIN_NAMESPACE class QLineEdit; QT_END_NAMESPACE class Button; class Calculator : public QDialog { Q_OBJECT public: Calculator(QWidget *parent = 0); private slots: void digitClicked(); void unaryOperatorClicked(); void additiveOperatorClicked(); void multiplicativeOperatorClicked(); void equalClicked(); void pointClicked(); 23 void changeSignClicked(); void backspaceClicked(); void clear(); void clearAll(); void clearMemory(); void readMemory(); void setMemory(); void addToMemory(); private: Button *createButton(const QString &text, const char *member); void abortOperation(); bool calculate(double rightOperand, const QString &pendingOperator); double sumInMemory; double sumSoFar; double factorSoFar; QString pendingAdditiveOperator; QString pendingMultiplicativeOperator; bool waitingForOperand; QLineEdit *display; enum { NumDigitButtons = 10 }; Button *digitButtons[NumDigitButtons]; }; #endif (4)头文件 button.h。在定义按键时会用到 Button 这个类。 #ifndef BUTTON_H #define BUTTON_H #include class Button : public QToolButton { Q_OBJECT public: Button(const QString &text, QWidget *parent = 0); QSize sizeHint() const; }; #endif (5)实现文件 button.cpp 文件。 #include #include "button.h" Button::Button(const QString &text, QWidget *parent) : QToolButton(parent) { setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Preferred); setText(text); 24 } QSize Button::sizeHint() const { QSize size = QToolButton::sizeHint(); size.rheight() += 20; size.rwidth() = qMax(size.width(), size.height()); return size; } (6)在“private slots”,申明了多个槽函数。对应按键加在后面,和计算器的功能都 一样: void digitClicked(); //数字按键 0-9 void unaryOperatorClicked(); //平方,求根号,倒数 void additiveOperatorClicked(); //“+”,“-” void multiplicativeOperatorClicked(); //“x”,“/” void equalClicked(); // "=" void pointClicked(); // "." void changeSignClicked(); //“+/-” void backspaceClicked(); // "Backspace" void clear(); // "Clear" void clearAll(); // "Clear All" void clearMemory(); // "MC" void readMemory(); // "MR" void setMemory(); // "MS" void addToMemory(); // "M+" (7)在私有区,申明了必须的成员函数和成员变量: private: Button *createButton(const QString &text, const char *member);//生成按键函数 void abortOperation();//运算错误 bool calculate(double rightOperand, const QString &pendingOperator);//运算函数(加 减乘除) double sumInMemory;//MC,MR,MS,M+值保存 double sumSoFar;//加法和减法运算值保存 double factorSoFar;//乘法和除法运算值保存 QString pendingAdditiveOperator;// 加法和减法运算符号保存 QString pendingMultiplicativeOperator;// 乘法和除法运算符号保存 bool waitingForOperand;//表示状态 QLineEdit *display;//数字显示框 enum { NumDigitButtons = 10 }; Button *digitButtons[NumDigitButtons];//数字按键 0-9 (8)类 Calculator 的实现文件 calculator.cpp,它包含了头文件中定义的所有函数和槽函 数的实现。 #include 25 #include #include "button.h" #include "calculator.h" Calculator::Calculator(QWidget *parent) : QDialog(parent) { sumInMemory = 0.0; sumSoFar = 0.0; factorSoFar = 0.0; waitingForOperand = true; display = new QLineEdit("0"); display->setReadOnly(true); display->setAlignment(Qt::AlignRight); display->setMaxLength(15); QFont font = display->font(); font.setPointSize(font.pointSize() + 8); display->setFont(font); for (int i = 0; i < NumDigitButtons; ++i) { digitButtons[i] = createButton(QString::number(i), SLOT(digitClicked())); } Button *pointButton = createButton(tr("."), SLOT(pointClicked())); Button*changeSignButton=createButton(tr("\261"),SLOT(changeSignClicked())); Button*backspaceButton=createButton(tr("Backspace"),SLOT(backspaceClicked())); Button *clearButton = createButton(tr("Clear"), SLOT(clear())); Button *clearAllButton = createButton(tr("Clear All"), SLOT(clearAll())); Button *clearMemoryButton = createButton(tr("MC"), SLOT(clearMemory())); Button *readMemoryButton = createButton(tr("MR"), SLOT(readMemory())); Button *setMemoryButton = createButton(tr("MS"), SLOT(setMemory())); Button *addToMemoryButton = createButton(tr("M+"), SLOT(addToMemory())); Button*divisionButton=createButton(tr("\367"),SLOT(multiplicativeOperatorClicked())); Button*timesButton=createButton(tr("\327"),SLOT(multiplicativeOperatorClicked())); Button *minusButton = createButton(tr("-"), SLOT(additiveOperatorClicked())); Button *plusButton = createButton(tr("+"), SLOT(additiveOperatorClicked())); Button*squareRootButton=createButton(tr("Sqrt"),SLOT(unaryOperatorClicked())); Button*powerButton= createButton(tr("x\262"), SLOT(unaryOperatorClicked())); Button*reciprocalButton=createButton(tr("1/x"),SLOT(unaryOperatorClicked())); Button *equalButton = createButton(tr("="), SLOT(equalClicked())); 26 QGridLayout *mainLayout = new QGridLayout; mainLayout->setSizeConstraint(QLayout::SetFixedSize); mainLayout->addWidget(display, 0, 0, 1, 6); mainLayout->addWidget(backspaceButton, 1, 0, 1, 2); mainLayout->addWidget(clearButton, 1, 2, 1, 2); mainLayout->addWidget(clearAllButton, 1, 4, 1, 2); mainLayout->addWidget(clearMemoryButton, 2, 0); mainLayout->addWidget(readMemoryButton, 3, 0); mainLayout->addWidget(setMemoryButton, 4, 0); mainLayout->addWidget(addToMemoryButton, 5, 0); for (int i = 1; i < NumDigitButtons; ++i) { int row = ((9 - i) / 3) + 2; int column = ((i - 1) % 3) + 1; mainLayout->addWidget(digitButtons[i], row, column); } mainLayout->addWidget(digitButtons[0], 5, 1); mainLayout->addWidget(pointButton, 5, 2); mainLayout->addWidget(changeSignButton, 5, 3); mainLayout->addWidget(divisionButton, 2, 4); mainLayout->addWidget(timesButton, 3, 4); mainLayout->addWidget(minusButton, 4, 4); mainLayout->addWidget(plusButton, 5, 4); mainLayout->addWidget(squareRootButton, 2, 5); mainLayout->addWidget(powerButton, 3, 5); mainLayout->addWidget(reciprocalButton, 4, 5); mainLayout->addWidget(equalButton, 5, 5); setLayout(mainLayout); setWindowTitle(tr("Calculator")); } 在类 Calculator 的构造函数中,首先在类的初始化列表中对成员变量进行了必要的初始 化。接着初始化 Qt 窗口部件的初始状态。在这步中 Qt 窗口的部件的信号关联到了相应的槽, 这里使用了函数 Button *createButton(const QString &text, const char *member);上面已经用 粗体表示,并对各个部件进行了布局,就是开始的时候看到的界面。 (9)button *createButton(const QString &text, const char *member)函数的实现。 Button *Calculator::createButton(const QString &text, const char *member) { 27 Button *button = new Button(text); connect(button, SIGNAL(clicked()), this, member); return button; } 函数*Calculator::createButton(const QString &text, const char *member)实现了创建一个 按钮并将部件的信号关联到了相应的槽,“connect(button, SIGNAL(clicked()), this, member);” 就实现了部件的信号关联到了相应的槽。 (10)依次看上面头文件里面提到的槽函数是如何实现的。 1)看一组 MC、MR、MS、M+这四个运算对应的槽函数。MC,MR,MS,M+值保存在 sumInMemory 这个变量里。如图 2-4: 图 2-4 M 系列按钮 ①MC 对应 void clearMemory(),这个函数很简单,sumInMemory 清零。 void Calculator::clearMemory() { sumInMemory = 0.0; } ②MR 对应 readMemory,把 sumInMemory 的值在 display 显示出来。 void Calculator::readMemory() { display->setText(QString::number(sumInMemory)); waitingForOperand = true; } ③MS 对应 void setMemory(),计算出运算值,将计算值保存到 sumInMemory。 void Calculator::setMemory() { equalClicked(); sumInMemory = display->text().toDouble(); 28 } ④M+对应 void addMemory(),计算出运算值,sumInMemory 累加上当前 display 中的值。 void Calculator::addToMemory() { equalClicked(); sumInMemory += display->text().toDouble(); } 2)数字输入区域有三个相关的槽函数,区域划分如图 2-5: 图 2-5 数字键按钮 ①将看到的是数字键 0-9 这 10 个按键的一个槽函数 void digitClicked()。 void Calculator::digitClicked() { Button *clickedButton = qobject_cast

    Top_arrow
    回到顶部
    EEWORLD下载中心所有资源均来自网友分享,如有侵权,请发送举报邮件到客服邮箱bbs_service@eeworld.com.cn 或通过站内短信息或QQ:273568022联系管理员 高进,我们会尽快处理。