




版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领
文档简介
Qt6.2/C++程序设计与桌面应用开发21世纪高等学校计算机类课程创新规划教材–微课视频版教材目录第1章初识Qt框架第2章Qt开发基础第3章界面设计组件第4章主框架窗口第5章对话框设计第6章事件系统第7章文件与数据库第8章模型/视图结构第9章图形绘制第10章多媒体编程第11章网络编程第12章进程与线程教材目录第11章网络编程11.1Qt网络模块11.2网络信息查询11.3HTTP编程11.4TCP编程11.5UDP编程11.1Qt网络模块Qt提供了多个与网络相关的模块,使用这些模块不仅可以开发出基于各种网络协议的应用程序,还可以轻松地将Web内容嵌入到Qt应用程序中,开发出具有Internet功能的混合桌面应用程序。11.1.1QtNetwork模块Qt的Network模块提供了用于编写TCP/IP客户端和服务器端程序的各种类,通过这些类可以实现特定的应用层协议。QtNetwork模块中的部分类及功能如表11.1所示。11.1.2QtWebSockets模块WebSocket是一种在单个TCP连接上进行全双工通信的协议。WebSocket使得客户端和服务器之间的数据交换变得更加简单,允许服务端主动向客户端推送数据。在WebSocketAPI中,浏览器和服务器只需要完成一次握手,两者之间就直接创建持久性的连接,并进行双向数据传输。Qt的WebSockets模块提供了WebSocket协议的实现,使用该模块中的类能够开发出基于WebSocket协议的网络应用程序,包括客户端和服务器。QtWebSockets模块包含4个C++类,它们是:QMaskGenerator、QWebSocket、QWebSocketServerQWebSocketCorsAuthenticatorQMaskGenerator类是一个自定义32位掩码生成器的抽象库;QWebSocket类表示实现与WebSocket协议对话的TCP套接字;QWebSocketServer类表示基于WebSocket协议的服务器实现;QWebSocketCorsAuthenticator类表示跨源请求(CrossOriginRequests,简称CORS)的身份验证器对象。下面是一个QWebSocket
和QWebSocketServer类的简单使用示例。11.1.3QtWebChannel模块Qt的WebChannel模块用于支持服务器(QML/C++应用程序)和客户端(HTML/JavaScript或QML应用程序)之间的对等通信。该模块提供了2个C++类,即QWebChannel和QWebChannelAbstractTransport类,以及一个名为qwebchannel.js的JavaScript库。QWebChannel用于将服务器应用程序的QObjects对象暴露给远程的HTML客户端;QWebChannelAbstractTransport类用于表示一个C++QWebChannel服务器和一个HTML/JS客户端之间的通信频道;qwebchannel.js库用于将C++和QML应用程序与HTML/JavaScript和QML客户端无缝集成。下面是一个简单的示例程序。11.1.4QtWebEngine模块Qt的WebEngine模块提供了一个web浏览器引擎,可以轻松地将万维网中的内容嵌入到没有本地web引擎的平台上的Qt应用程序中。该模块为Qt提供了对广泛的标准Web技术的支持,这些技术可以将用CSS样式化并用JavaScript脚本化的HTML内容嵌入到Qt应用程序中。QtWebEngine模块促进了HTML网页与传统的基于QWidget的桌面应用程序的集成。QtWebEngine提供了Qt应用程序中动态web内容区域的呈现功能,它由3个子模块组成,分别为QtWebEngineWidgets、QtWebEngine和QtWebEngineCore。这些子模块的作用及相关C++类的使用方法,请参见Qt的帮助文档。下面是一个QtWebEngine模块的简单使用示例。11.1.5QtWebView模块Qt的WebView模块用于在QML应用程序中显示Web内容,常用于基于Android、IOS操作系统的移动平台中。由于本教材没有介绍QML编程,请大家自行运行教材给出的示例代码项目code_11_1_5,该项目来自于Qt实例minibrowser。图11.4为项目运行结果。11.2网络信息查询与网络有关的信息有很多,其中主要的是网络接口信息,也就是网络中主机的相关信息。在QtNetwork模块中,QHostInfo
和QNetworkInterface类用于获取网络接口信息。11.2.1使用QHostInfo类QHostInfo类用于查找与主机名关联的IP地址,或与IP地址关联的主机名。其部分成员函数名称及功能如表11.2所示。【例11.1】编写一个Qt应用程序,使用QHostInfo类来查询主机信息。(1)启动QtCreator集成开发环境,创建一个名为examp11_1的Qt应用程序,设置应用程序主窗口基类为QMainWindow。(2)双击mainwindow.ui界面文件打开QtDesigner界面设计工具,在应用程序主窗口中放置一个QPlainTextEdit文本编辑器部件和一个QPushButton按钮部件,对象名称分别为plainTextEdit和pushButton。布局效果如图11.5所示。(3)选择主窗口中的pushButton按钮,为其添加一个与clicked()信号关联的槽函数,函数名称为on_pushButton_clicked();另外,再添加一个测试用槽函数lookedUp()。两个槽函数的声明代码如下所示:(4)在槽函数on_pushButton_clicked()中添加代码,获取本地主机信息。代码如下所示。(5)在槽函数lookedUp()中添加代码,获取远程主机信息。代码如下所示。(6)连接网络,构建并运行程序。11.2.2使用QNetworkInterface类QNetworkInterface类提供一个主机IP地址和网络接口列表,可以通过该列表来获取相关网络信息。其部分成员函数及功能如表11.3所示。【例11.2】编写一个Qt应用程序,使用QNetworkInterface类来查询主机信息。(1)复制例11.1中的应用程序examp11_1,将项目名称修改为examp11_2。删除程序中的lookedUp()槽函数,以及on_pushButton_clicked()函数中的代码。(2)修改应用程序主窗口标题以及主窗口中按钮的标题,如图11.6所示。(3)在on_pushButton_clicked()函数中添加如下代码。(4)构建并运行程序。11.3HTTP编程网络应用程序的开发分为低级和高级两个层次;低层次开发基于网络的传输层协议,例如TCP和UDP协议,实现的是低层的网络进程通信(Socket通信)的功能;高层次开发基于应用层的网络协议,例如HTTP、FTP和SMTP等,它们运行在TCP/UDP传输协议之上,在低层Socket通信的基础上进一步实现应用型的协议功能。11.3.1相关Qt类基于HTTP协议的网络应用程序的开发,需要使用QtNetwork模块提供的一些实现高层网络操作的类;如QNetworkRequest、QNetworkAccessManager和QNetworkRely等。1、QNetworkRequest类在Qt中,使用QNetworkRequest类来表示一个网络访问请求,同时保存该网络请求的相关信息。作为与请求有关的信息的统一容器,在创建请求对象时指定的URL决定了请求使用的协议,目前支持HTTP、HTTPS、FTP和本地文件URLs的下载或上传。QNetworkRequest类的部分成员函数及功能,如表11.4所示。2、QNetworkAccessManager类该类用于协调网络操作。在QNetworkRequest类发起一个网络访问请求后,QNetworkAccessManager类负责发送该请求、创建网络响应,并发送信号来报告网络通信的进度。QNetworkAccessManager类的部分成员函数及功能如表11.5所示。3、QNetworkReply类Qt用QNetworkReply类来表示网络请求的响应,它由QNetworkAccessManager类在完成请求调度后创建QNetworkReply类提供了像finished()、readyRead()和downloadProgress()等信号,使用这些信号,可以实现对网络响应执行情况的监测,并执行相应操作。QNetworkReply类的部分成员函数如表11.6所示。11.3.2HTTP访问HTTP(HyperTextTransferProtocol,超文本传输协议)是一个客户端和服务器端请求和应答的标准。可以使用QNetworkRequest、QNetworkAccessManager
和QNetworkReply类
来实现Qt应用程序的HTTP访问功能。【例11.3】编写一个Qt应用程序,实现简单Web浏览器功能。(1)启动QtCreator集成开发环境,创建一个名为examp11_3的Qt应用程序,设置应用程序主窗口基类为QMainWindow。(2)双击mainwindow.ui界面文件打开QtDesigner界面设计工具,删除应用程序主窗口中的菜单栏与状态栏。在应用程序主窗口中放置一个QLabel标签、一个QLineEdit单行文本输入框、一个名为“访问”的QPushButton按钮和一个QPlainTextEdit文本编辑器部件,对象名称分别为label、lineEdit、pushButton和plainTextEdit。布局效果如图11.7所示。(3)为主窗口中的“访问”按钮添加clicked()信号槽函数,函数名为on_pushButton_clicked();另外,再添加一个名为replyFinished()的槽函数。这两个槽函数的声明代码如下:privateslots:voidreplyFinished(QNetworkReply*reply);voidon_pushButton_clicked();(4)为MainWindow类添加2个私有成员变量,如下所示。private:…QNetworkAccessManager*manager;QNetworkRequestrequest;(5)在MainWindow类的构造函数中添加如下代码。manager=newQNetworkAccessManager(this);connect(manager,SIGNAL(finished(QNetworkReply*)),this,SLOT(replyFinished(QNetworkReply*)));这里,finished(QNetworkReply*)是QNetworkAccessManager的信号,该信号在响应完成后自动发送。(6)编写on_pushButton_clicked()槽函数代码,如下所示。(7)编写replyFinished()槽函数代码,如下所示。(8)构建并运行程序。11.3.3HTTP下载基于HTTP协议的网络文件下载与上述HTTP访问相似,只要将请求后获取到的响应内容存储在指定的文件中即可。【例11.4】编写一个Qt应用程序,实现简单的Web文件下载功能。(1)启动QtCreator集成开发环境,创建一个名为examp11_4的Qt应用程序,设置应用程序主窗口基类为QMainWindow。(2)双击mainwindow.ui界面文件打开QtDesigner界面设计工具,删除主窗口中的菜单栏与状态栏。在应用程序主窗口中放置3个QLabel标签、2个QLineEdit单行文本编辑框、2个QPushButton按钮、1个QCheckBox按钮和1个QPrecess进度条部件。布局效果如图11.9所示。(3)在MainWindow类中添加成员变量及槽函数,如下所示。(4)在MainWindow类的实现文件中添加代码,实现程序功能。如下所示。(5)构建并运行程序。11.4TCP编程TCP(TransmissionControlProtocol,传输控制协议)是一个用于数据传输的低层网络协议,多个互联网协议(如HTTP、FTP等)都是基于该协议的。TCP是一个面向数据流和连接的可靠传输协议,特别适合用于连续数据的传输。TCP编程一般分为客户端和服务器端,即使用C/S(Client/Server)模型。11.4.1相关Qt类在QtNetwork模块类中,有2个与TCP直接相关的类QTcpSocket
和QTcpServer。QTcpSocket
用于建立TCP连接后使用套接字(Socket)进行通信;QTcpServer用于服务器端建立网络监听,创建网络Socket连接。1、QTcpSocket类QTcpSocket类为TCP提供一个接口,用于建立TCP连接并传输数据流。其继承关系如图11.10所示。2、QTcpServer类QTcpServer类提供基于TCP的服务器。该类继承自QObject,并被QScptServer类继承。其部分成员函数及功能如表11.8所示。11.4.2服务器端编程服务器端程序首先需要用QTcpServer::listen()开始服务器端监听,可以指定监听的IP地址和端口,一般一个服务程序只监听某个端口的网络连接。当有新的客户端接入时,QTcpServer内部的incomingConnection()函数会创建一个与客户端连接的QTcpSocket对象,然后发射信号newConnection()。在newConnection()信号的槽函数中,可以用nextPendingConnection()接受客户端的连接,然后使用QTcpSocket与客户端进行通信。【例11.5】编写一个Qt应用程序,演示基于TCP协议的服务器端程序设计方法。(1)启动QtCreator集成开发环境,创建一个名为examp11_5的Qt应用程序,设置应用程序主窗口基类为QWidget。(2)双击widget.ui界面文件打开QtDesigner界面设计工具,在应用程序主窗口中放置一个QListWidget列表框、一个QLabel标签、一个QLineEdit单行文本编辑框和一个QPushButton按钮部件,其对象名称分别为listWidget、label、lineEdit和pushButton。布局效果如图11.11所示。(3)在项目中添加一个名为Server的C++类,其头文件server.h和实现文件server.cpp如下所示。(4)在项目中添加一个名为Client的C++类,其头文件client.h和实现文件client.cpp如下所示。(5)在Widget类中添加私有成员变量server,以及私有槽函数on_pushButton_clicked()和updateServer()。其声明代码如下所示。(6)在Widget类的构造函数中添加代码,并实现上述(5)中的2个槽函数功能。如下所示。(7)构建并运行程序,单击“启动服务器”按钮启动服务器。(8)为了对服务器端程序进行测试,需要运行客户端应用程序。运行教材源码中的examp11_6应用程序(例11.6中的客户端应用程序),如图11.12所示。11.4.3客户端编程客户端应用程序的编程非常简单,只需要使用一个QTcpSocket对象,即可和服务器端程序进行通信。【例11.6】编写一个Qt应用程序,演示基于TCP协议的客户端程序设计方法。程序运行结果如图11.13和图11.14所示。这里启动了2个客户端应用程序。(1)启动QtCreator集成开发环境,创建一个名为examp11_6的Qt应用程序,设置应用程序主窗口基类为QWidget。(2)双击widget.ui界面文件打开QtDesigner界面设计工具,在应用程序主窗口中放置部件并使用布局管理器进行布局。主窗口中部件类型及对象名称如如图11.15所示。(3)在Widget类中添加私有成员变量和槽函数,其声明代码如下所示。(4)在Widget类的构造函数中添加代码,并实现上述(3)中的5个槽函数功能。如下所示。(5)构建并运行程序。11.5UDP编程UDP(UserDatagramProtocol,用户数据报协议)是轻量的、不可靠的、面向数据报(datagram)、无连接的协议,它可以用于对可靠性要求不高的场合。与TCP通信不同,两个程序之间进行UDP通信无需预先建立持久的socket连接,UDP每次发送数据报都需要指定目标地址和端口。Qt中的UDP通信通过QUdpSocket类来实现。11.5.1QUdpSocket类与QTcpSocket一样,QUdpSocket也是从QAbstractSocket类派生出来的,其继承关系如图11.10所示。除了继承下来的函数之外,QUdpSocket还定义了一些特有的成员函数,如表11.9所示。11.5.2UDP单播UDP消息传送有单播、广播、组播三种模式,其示意图如图11.16所示。【例11.7】编写一个Qt应用程序,演示基于UDP协议的网络通信功能的实现方法。(1)启动QtCreator集成开发环境,创建一个名为examp11_7的Qt应用程序,设置应用程序主窗口基类QWidget。(2)双击widget.ui界面文件打开QtDesigner界面设计工具,在应用程序主窗口中放置部件并使用布局管理器进行布局。主窗口中部件对象类型及名称如图11.19所示。(3)打开examp11_7.pro项目文件,添加QtNetwork模块支持。如下所示。QT+=network(4)在Widget类中添加私有成员变量、成员函数和槽函数,其声明代码如下所示。(5)在Widget类的构造函数中添加代码,并实现上述(4)中的5个函数功能。如下所示。(5)构建并运行程序。11.5.3UDP组播UDP组播是主机之间“一对一组”的通信模式。组播报文的目的地址使用D类IP地址,D类地址不能出现在IP报文的源IP地址字段。用同一个IP多播地址接收多播数据报的所有主机构成了一个组,称为多播组或组播组。所有的信息接收者都加入到一个组内,并且一旦加入之后,流向组地址的数据报立即开始向接收者传输,组中的所有成员都能接收到数据报。组中的成员是动态的,主机可以在任何时候加入和离开组播组。【例11.8】编写一个Qt应用程序,演示基于UDP协议的网络组播通信功能的实现方法。(1)启动QtCreator集成开发环境,创建一个名为examp11_8的Qt应用程序,设置应用程序主窗口基类QWidget。(2)双击widget.ui界面文件打开QtDesigner界面设计工具,在应用程序主窗口中放置部件并使用布局管理器进行布局。主窗口中部件对象类型及名称如图11.22所示。(3)打开examp11_8.pro项目文件,添加QtNetwork模块支持。如下所示。QT+=network(4)在Widget类中添加私有成员变量、成员函数和槽函数,其声明代码如下所示。(5)在Widget类的构造函数中添加代码,并实现上述(4)中的函数功能。如下所示。(5)构建并运行程序。课后作业思政本章结束Qt6.2/C++程序设计与桌面应用开发21世纪高等学校计算机类课程创新规划教材–微课视频版教材目录第1章初识Qt框架第2章Qt开发基础第3章界面设计组件第4章主框架窗口第5章对话框设计第6章事件系统第7章文件与数据库第8章模型/视图结构第9章图形绘制第10章多媒体编程第11章网络编程第12章进程与线程教材目录第12章进程与线程12.1相关Qt类12.2进程12.3线程12.4线程控制12.1相关Qt类Qt对进程和线程的支持是通过一系列的类协同实现的,其中主要的有QProcess类和QThread类。QProcess类用来启动一个进程并与其进行通信;QThread类提供不依赖于平台的管理线程常用方法。12.1.1QProcess类QProcess类属于Qt的core模块中,它是QIODevice类的直接子类,属于Qt的顺序访问I/O设备;同时,QProcess类也是QObject的子类,因而具有Qt的信号/槽功能。其继承关系如图12.1所示。QProcess类提供了大量的函数实现进程的启动、控制、查询、设置及通信等功能。其部分成员函数及功能如表12.1所示。下面是一段使用QProcess启动cmd.exe控制台程序并执行dir命令的示例代码。12.1.2QThread类QThread类直接继承自QObject类,每个QThread对象代表了一个在应用程序中可以独立控制的线程,这个线程与进程中的其他线程分享数据。表12.2给出了QThread类的部分非继承成员函数及功能。下面是一段使用QThread类实现多线程的示例代码。12.2进程进程(Process)是计算机中的程序关于数据集合上的一次运行活动,是正在运行的程序的实例。从理论角度来看,进程是对正在运行的程序过程的抽象;从实现角度来看,进程就是一种数据结构。进程清晰地刻画了动态系统的内在规律,并有效地管理和调度进入计算机系统主存储器运行的程序。12.2.1进程的启动进程是一个“执行中的程序”,所以,启动进程就是开始运行一个程序。可以使用QProcess类的start()、startDetached()和execute()函数来启动一个进程。下面是一个在Qt应用程序中打开/关闭Windows系统计算器的简单实例。【例12.1】编写一个Qt应用程序,在程序中运行Windows计算器。(1)打开QtCreator集成开发环境,创建一个基于QWidget类的Qt应用程序。项目名称为examp12_1。(2)双击项目视图中的widget.ui界面文件,打开QtDesigner设计工具,对程序主窗口界面进行设计。在主窗口中添加1个QPlainTextEdit类型的多文本编辑器,和2个QPushButton类型的按钮。3个对象的名称分别为plainTextEdit、startButton和closeButton。(3)为2个QPushButton按钮添加clicked()信号的槽函数,函数名称分别为on_startButton_clicked()和on_closeButton_clicked()。(4)打开widget.h头文件,为Widget类添加一个名为isActive()的私有成员函数,用于判断计算器是否已经启动;添加一个名为showError()的槽函数,用于显示启动进程时可能会出现的错误信息;添加3个名称为myProcess、program和arguments的私有成员变量,分别表示进程、外部程序以及命令行参数。代码如下所示。(5)打开widget.cpp文件,编写构造函数、自定义函数,以及槽函数代码,以实现程序功能。如下所示。(6)构建并运行程序。12.2.2进程间通信Qt提供了多种方法在Qt应用程序中实现进程间通信(IPC,Inter-ProcessCommunication)。主要有:1、TCP/IP方法2、LocalServer/Socket方法3、SharedMemory方法4、D-Bus协议方法5、QProcess方法6、SessionManagement方法1、TCP/IP方法跨平台的QtNetwork模块提供了众多的类来实现网络编程。它不仅提供了使用特定应用程序级协议进行通信的高级类(如QNetworkAccessManager),也提供了用于实现相关协议的低级类(如QTcpSocket、QTcpServer、QSslSocket)。本教材的第11章网络编程中详细介绍了此种方法。2、LocalServer/Socket方法跨平台的QtNetwork模块提供了使本地网络编程可移植且容易的类。它提供了QLocalServer
和QLocalSocket类,允许在本地设置中进行类似网络的通信。【例12.2】编写一个Qt应用程序,通过LocalServer/Socket方法来实现进程之间的通信。(1)打开QtCreator集成开发环境,创建2个基于QDialog类的Qt应用程序。项目名称分别为examp12_1_server和examp12_1_client。前者表示服务器端程序,后者表示客户端程序。(2)编写服务器端程序代码。下面只给出部分关键代码,其他请参见教材源码。(3)编写客户端程序代码。下面只给出部分关键代码,其他请参见教材源码。(4)构建并运行程序。3、SharedMemory方法QtNetwork模块中的跨平台的QSharedMemory
共享内存类,提供对操作系统的共享内存的实现,它允许多个线程和进程安全访问共享内存段。QSystemSemaphore也可以用来控制访问由系统共享的资源以及进程之间的通信。【例12.3】编写一个Qt应用程序,使用共享内存来实现进程之间的通信。(1)打开QtCreator集成开发环境,创建一个基于QWidget类的Qt应用程序。项目名称为examp12_3。(2)双击项目视图中的widget.ui界面文件,打开QtDesigner设计工具,对程序主窗口界面进行设计。在主窗口中添加1个QLabel标签控件,和2个QPushButton类型的按钮。3个对象的名称分别为label、loadFromFileButton和loadFromSharedMemoryButton。(3)为2个QPushButton按钮添加clicked()信号的槽函数,函数名称分别为on_loadFromFileButton_clicked()和on_loadFromSharedMemoryButton_clicked()。(4)打开widget.h头文件,为Widget类添加一个名为detach()的私有成员函数,用于将进程与共享内存段分离;添加一个名为sharedMemory的QSharedMemory私有成员对象,用于表示共享内存段。代码如下。private:voiddetach();private:…QSharedMemorysharedMemory;(5)打开widget.cpp文件,编写构造函数、自定义函数,以及槽函数代码,以实现程序功能。如下所示。(4)构建并运行程序。4、D-Bus协议方法Qt的D-Bus模块是一种可用于使用D-Bus协议实现IPC的唯一Unix库。它将Qt的信号和槽机制延伸到IPC级别,允许由一个进程发出的信号被连接到另一个进程的槽。该方法的实现,请参见Qt的示例程序D-BusChatExample和D-BusRemoteControlledCarExample5、QProcess方法跨平台类QProcess能够用于启动外部程序作为子进程,并与它们进行通讯。它提供了用于监测和控制该子进程状态的API。另外,QProcess为从QIODevice继承的子进程提供了输入/输出通道。该方法的实现,请参见上面12.1.1小节中的code_12_1_1示例项目。6、SessionManagement方法在Linux/X11平台上,Qt提供了会话管理的支持。会话容许事件传播到进程,例如,当检测到关机时,进程和应用程序能够执行任何必须的操作,如保存打开的文档等。12.3线程Qt对线程的支持是通过三个方面来实现的:一是提供了一组与平台无关的线程类,二是提供了一个线程安全的事件发送方式,三是提供了跨线程的信号与槽的关联。Qt对多线程操作的全面支持,使得开发可移植的Qt多线程应用程序变得非常容易,同时还可以充分发挥多处理器中各个内核的效用。12.3.1线程的运行在Qt的多线程应用程序中,通常使用QThread类提供的方法来对线程进行管理。一个QThread类的对象管理一个线程,默认情况下,线程是在QThread::run()函数中开始运行的,run()函数通过调用exec()启动并运行Qt的事件循环。1、线程的创建在多线程编程中,将应用程序的线程称为主线程,额外创建的线程称为工作线程。工作线程可以通过两种方法来创建:一种方法是自定义QThread类的子类,并重载run()函数;另一种方法是先创建工作对象,然后使用QObject::moveToThread()函数将工作对象嵌入到线程中。(1)使用QThread子类对象通过子类化QThread来创建工作线程,是Qt多线程编程中的常用方法。下面是一段示例代码。(2)使用QObject::moveToThread()函数通过这种方法创建工作线程,首先需要创建一个工作者对象,将线程任务集中到这个对象中,然后使用QObject::moveToThread()函数完成工作线程的创建。示例如下。2、线程的启动工作线程创建完成后,可以在外部创建该线程的实例,然后调用start()函数来开始执行该线程,start()默认会调用run()函数。下面来看一个简单的实例。【例12.4】编写一个Qt应用程序,统计n个自然数中质数的个数。要求统计计算在单独的线程中完成,主线程接收用户输入并显示统计结果。(1)打开QtCreator集成开发环境,创建一个基于QWidget类的Qt应用程序。项目名称为examp12_4。(2)双击项目视图中的widget.ui界面文件,打开QtDesigner设计工具,对程序主窗口界面进行设计。在主窗口中添加2个QLabel标签、1个QPushButton按钮、1个QLineEdit单行文本输入框和1个QPlainTextEdit多行文本编辑器。其中,单行文本输入框、按钮和多行文本编辑器控件对象的名称分别为lineEdit、pushButton和plainTextEdit。(3)右击主窗口中的lineEdit控件,选择快捷菜单中的“Gotoslots…”菜单命令,为单行文本控件添加editingFinished信号关联槽函数on_lineEdit_editingFinished();使用同样的方法,为“计算”按钮控件添加clicked信号关联槽函数on_pushButton_clicked()。(4)在项目中添加一个QThread类的派生类MyThread,并重载run()虚函数。为类MyThread添加私有成员变量endNum,用于存储需要统计的自然数的个数;为endNum成员变量添加公有的设置函数setEndNum()。代码如下所示。接着,编写mythread.cpp文件中的代码,完成成员变量的初始化、成员变量的设置和线程任务等工作。代码如下所示。(5)打开widget.h文件,在类Widget中添加一个MyThread类型的对象myThread,并为上述第(3)步中创建的2个槽函数添加代码,实现相应的功能。如下所示。(6)构建并运行程序。程序运行后,输入不同的n值,并单击“计算”按钮进行测试,结果如图12.10所示。该程序子线程中的计算结果是直接在控制台输出的,如果要将计算结果传递到主线程中,就需要了解线程间通信的基本方法。12.3.2线程间通信线程间的通信一般通过两种方法来实现,即成员变量方法和自定义信号方法。成员变量方法就是通过线程对象的成员变量来返回线程数据;自定义信号方法通过在线程类中定义信号,利用信号参数来传递线程数据。1、成员变量方法由于线程任务是在run()函数中完成的,而run()函数又属于线程类的成员函数,所以可以通过线程类的成员变量来存储run()函数中的相关数据。【例12.5】编写一个Qt应用程序,使用成员变量来实现线程之间的通信。(1)复制例12.4中的项目examp12_4,并将名称修改为examp12_5。(2)打开项目中的mythread.h文件,在MyThread线程类中添加一个类型为long的私有成员变量result,并为其添加公有的getResult()函数。getResult()函数实现代码如下:longMyThread::getResult(){returnresult;}(3)修改run()函数中的代码,将计算结果赋值给成员变量result。如下所示。voidMyThread::run(){…//qDebug()<<"在1~"<<endNum<<"的n个自然数中,质数的个数为:"<<n;result=n;}(4)打开项目中的widget.h文件,在类Widget中添加槽函数returnResult()。其实现代码如下所示:voidWidget::returnResult(){longr=myThread.getResult();QStringstr;str.setNum(r);ui->plainTextEdit->insertPlainText(str);}(5)在Widget类的构造函数中编写代码,将槽函数returnResult()和QThread::finished信号关联。代码如下:connect(&myThread,&QThread::finished,this,&Widget::returnResult);子线程运行结束后,即刻调用主窗口中的returnResult()槽函数,将计算结果显示在多行文本编辑器光标所在的位置。(6)构建并运行程序。程序运行后,在文本输入框中输入n并回车,然后单击“计算”按钮开始统计计算。程序计算时,可以在主窗口中进行其他操作,主线程没有被阻塞。如图12.12所示。2、自定义信号方法在Qt的信号与槽通讯机制中,对象在发射信号的时候是可以附带传送一些参数的。所以,可以通过在线程类中定义信号,利用信号参数来传递线程数据。【例12.6】编写一个Qt应用程序,使用自定义信号方法实现线程之间的通信。(1)复制例12.4中的项目examp12_4,并将名称修改为examp12_6。(2)打开项目中的mythread.h头文件,为线程类MyThread添加一个信号函数。代码如下:signals:voidreturnResult(longresult);(3)打开项目中的mythread.cpp文件,修改线程类MyThread的run()函数中的代码,如下所示。voidMyThread::run(){…//qDebug()<<"在1~"<<endNum<<"的n个自然数中,质数的个数为:"<<n;emitreturnResult(n);}(4)打开项目文件widget.h,在类Widget中添加槽函数getResult(),并编写其实现代码。如下所示。voidWidget::getResult(longresult){longr=result;QStringstr;str.setNum(r);ui->plainTextEdit->insertPlainText(str);}(5)在Widget类的构造函数中编写代码,将槽函数getResult()和MyThread::returnResult信号关联。代码如下:connect(&myThread,&MyThread::returnResult,this,&Widget::getResult);(6)构建并运行程序。12.4线程控制线程之间存在着互相制约的关系,具体可以分为互斥和同步这两种关系。在Qt中,线程的互斥与同步控制,可以使用QMutex、QMutexLocker、QReadWriteLock、QReadLocker、QWriteLocker、Qsemaphore和QWaitCondition
等类来实现。12.4.1基于互斥量互斥量可以通过Qmutex
或QMutexLocker类实现。Qmutex和QMutexLocker
又称为互斥锁,用于保护共享资源(如对象、数据结构和代码段等),它们能够保证多线程程序中在同一时刻只有一个线程访问共享资源。【例12.7】编写一个Qt应用程序,示例使用互斥量保护共享资源。(1)打开QtCreator集成开发环境,创建一个基于QWidget类的Qt应用程序,项目名称为examp12_7。(2)在项目中添加一个名为TestData的C++类,并在该类中定义2个静态成员sharedNumber和sharedNumMutex,前者表示共享整型数据;后者表示互斥锁。代码如下。(3)在项目中添加2个QThread的子线程类,类名分别为WorkThread1和WorkThread2。在这两个类中实现QThread::run()虚函数,代码如下。(4)在项目主窗口中添加一个QPushButton类型的按钮,并在其clicked()信号对应的槽函数中编写代码,如下所示。voidWidget::on_pushButton_clicked(){m_workThread2.start();//先启动线程2m_workThread1.start();}(5)构建并运行程序。为了对比运行结果,程序运行测试分两次来进行。先注释掉上述(3)步代码中的语句1、语句5和语句9,测试不使用互斥锁的情形,结果如图12.14所示。从输出结果可以看出,在线程1中输出的结果为17(0+2+20-5),这个结果是执行了语句6、语句2和语句3后得到的。也就是说,在线程2还没有对共享数据TestData::sharedNumber修改(语句7还没有执行)完成的时候,线程1便对该共享数据进行了修改。很显然这个计算结果是不符合程序设计者的初衷的。接着,测试使用互斥锁后程序的运行情况。取消语句1、语句5和语句9的注释,重新构建并运行程序,结果如图12.15所示。从结果可以看到,使用互斥锁以后,线程1就不能在线程2访问共享数据的时候对其进行操作了。这样有效保护了程序
温馨提示
- 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
- 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
- 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
- 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
- 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
- 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
- 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
最新文档
- 2025年电商绿色物流行业绿色物流服务创新与模式探索报告
- 2024年《陈情表》教案锦集8篇
- 2025年消费金融市场规模扩张与风险防控关键指标监测报告
- 细胞治疗产品临床试验审批流程中的临床数据管理报告
- 互联网养老服务平台项目技术创新与产业升级研究报告
- 数字化时代下2025年金融机构风险管理的风险控制技术创新与应用报告
- 2023造价工程师考试《土建工程》试题及答案
- Unit+6+Earth+first+Using+language+非谓语做补语+2025-2026学年高中英语外研版(2019)必修第二册
- 2025年江西省宜春市十校联考九年级学业水平模拟考试生物试题(含答案)
- 2025版智能化顶管施工与信息化管理合同
- 外墙保温工程质量验收管理规范
- ISO27001:2022信息安全管理体系全套文件+表单
- 2025年成都市锦江投资发展集团有限责任公司招聘笔试参考题库附带答案详解
- 挤压车间生产工艺流程
- 港航疏浚事业部直属项目工程分包管理办法
- 成都市公安局锦江区分局招聘警务辅助人员真题
- 企业搬迁重置规划范文
- 风电场道路维护与管理方案
- 四川省成都市2024-2025学年下册新七年级分班(奖学金)数学模拟试题(附答案)
- 高中历史说课课件
- 干部履历表填写范本(中共中央组织部1999年)
评论
0/150
提交评论