版權說明:本文檔由用戶提供并上傳,收益歸屬內容提供方,若內容存在侵權,請進行舉報或認領
文檔簡介
Qt6.2/C++程序設計與桌面應用開發(fā)21世紀高等學校計算機類課程創(chuàng)新規(guī)劃教材–微課視頻版教材目錄第1章初識Qt框架第2章Qt開發(fā)基礎第3章界面設計組件第4章主框架窗口第5章對話框設計第6章事件系統第7章文件與數據庫第8章模型/視圖結構第9章圖形繪制第10章多媒體編程第11章網絡編程第12章進程與線程教材目錄第11章網絡編程11.1Qt網絡模塊11.2網絡信息查詢11.3HTTP編程11.4TCP編程11.5UDP編程11.1Qt網絡模塊Qt提供了多個與網絡相關的模塊,使用這些模塊不僅可以開發(fā)出基于各種網絡協議的應用程序,還可以輕松地將Web內容嵌入到Qt應用程序中,開發(fā)出具有Internet功能的混合桌面應用程序。11.1.1QtNetwork模塊Qt的Network模塊提供了用于編寫TCP/IP客戶端和服務器端程序的各種類,通過這些類可以實現特定的應用層協議。QtNetwork模塊中的部分類及功能如表11.1所示。11.1.2QtWebSockets模塊WebSocket是一種在單個TCP連接上進行全雙工通信的協議。WebSocket使得客戶端和服務器之間的數據交換變得更加簡單,允許服務端主動向客戶端推送數據。在WebSocketAPI中,瀏覽器和服務器只需要完成一次握手,兩者之間就直接創(chuàng)建持久性的連接,并進行雙向數據傳輸。Qt的WebSockets模塊提供了WebSocket協議的實現,使用該模塊中的類能夠開發(fā)出基于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應用程序中動態(tài)web內容區(qū)域的呈現功能,它由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所示?!纠?1.1】編寫一個Qt應用程序,使用QHostInfo類來查詢主機信息。(1)啟動QtCreator集成開發(fā)環(huán)境,創(chuàng)建一個名為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編程網絡應用程序的開發(fā)分為低級和高級兩個層次;低層次開發(fā)基于網絡的傳輸層協議,例如TCP和UDP協議,實現的是低層的網絡進程通信(Socket通信)的功能;高層次開發(fā)基于應用層的網絡協議,例如HTTP、FTP和SMTP等,它們運行在TCP/UDP傳輸協議之上,在低層Socket通信的基礎上進一步實現應用型的協議功能。11.3.1相關Qt類基于HTTP協議的網絡應用程序的開發(fā),需要使用QtNetwork模塊提供的一些實現高層網絡操作的類;如QNetworkRequest、QNetworkAccessManager和QNetworkRely等。1、QNetworkRequest類在Qt中,使用QNetworkRequest類來表示一個網絡訪問請求,同時保存該網絡請求的相關信息。作為與請求有關的信息的統一容器,在創(chuàng)建請求對象時指定的URL決定了請求使用的協議,目前支持HTTP、HTTPS、FTP和本地文件URLs的下載或上傳。QNetworkRequest類的部分成員函數及功能,如表11.4所示。2、QNetworkAccessManager類該類用于協調網絡操作。在QNetworkRequest類發(fā)起一個網絡訪問請求后,QNetworkAccessManager類負責發(fā)送該請求、創(chuàng)建網絡響應,并發(fā)送信號來報告網絡通信的進度。QNetworkAccessManager類的部分成員函數及功能如表11.5所示。3、QNetworkReply類Qt用QNetworkReply類來表示網絡請求的響應,它由QNetworkAccessManager類在完成請求調度后創(chuàng)建QNetworkReply類提供了像finished()、readyRead()和downloadProgress()等信號,使用這些信號,可以實現對網絡響應執(zhí)行情況的監(jiān)測,并執(zhí)行相應操作。QNetworkReply類的部分成員函數如表11.6所示。11.3.2HTTP訪問HTTP(HyperTextTransferProtocol,超文本傳輸協議)是一個客戶端和服務器端請求和應答的標準??梢允褂肣NetworkRequest、QNetworkAccessManager
和QNetworkReply類
來實現Qt應用程序的HTTP訪問功能?!纠?1.3】編寫一個Qt應用程序,實現簡單Web瀏覽器功能。(1)啟動QtCreator集成開發(fā)環(huán)境,創(chuàng)建一個名為examp11_3的Qt應用程序,設置應用程序主窗口基類為QMainWindow。(2)雙擊mainwindow.ui界面文件打開QtDesigner界面設計工具,刪除應用程序主窗口中的菜單欄與狀態(tài)欄。在應用程序主窗口中放置一個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的信號,該信號在響應完成后自動發(fā)送。(6)編寫on_pushButton_clicked()槽函數代碼,如下所示。(7)編寫replyFinished()槽函數代碼,如下所示。(8)構建并運行程序。11.3.3HTTP下載基于HTTP協議的網絡文件下載與上述HTTP訪問相似,只要將請求后獲取到的響應內容存儲在指定的文件中即可。【例11.4】編寫一個Qt應用程序,實現簡單的Web文件下載功能。(1)啟動QtCreator集成開發(fā)環(huán)境,創(chuàng)建一個名為examp11_4的Qt應用程序,設置應用程序主窗口基類為QMainWindow。(2)雙擊mainwindow.ui界面文件打開QtDesigner界面設計工具,刪除主窗口中的菜單欄與狀態(tài)欄。在應用程序主窗口中放置3個QLabel標簽、2個QLineEdit單行文本編輯框、2個QPushButton按鈕、1個QCheckBox按鈕和1個QPrecess進度條部件。布局效果如圖11.9所示。(3)在MainWindow類中添加成員變量及槽函數,如下所示。(4)在MainWindow類的實現文件中添加代碼,實現程序功能。如下所示。(5)構建并運行程序。11.4TCP編程TCP(TransmissionControlProtocol,傳輸控制協議)是一個用于數據傳輸的低層網絡協議,多個互聯網協議(如HTTP、FTP等)都是基于該協議的。TCP是一個面向數據流和連接的可靠傳輸協議,特別適合用于連續(xù)數據的傳輸。TCP編程一般分為客戶端和服務器端,即使用C/S(Client/Server)模型。11.4.1相關Qt類在QtNetwork模塊類中,有2個與TCP直接相關的類QTcpSocket
和QTcpServer。QTcpSocket
用于建立TCP連接后使用套接字(Socket)進行通信;QTcpServer用于服務器端建立網絡監(jiān)聽,創(chuàng)建網絡Socket連接。1、QTcpSocket類QTcpSocket類為TCP提供一個接口,用于建立TCP連接并傳輸數據流。其繼承關系如圖11.10所示。2、QTcpServer類QTcpServer類提供基于TCP的服務器。該類繼承自QObject,并被QScptServer類繼承。其部分成員函數及功能如表11.8所示。11.4.2服務器端編程服務器端程序首先需要用QTcpServer::listen()開始服務器端監(jiān)聽,可以指定監(jiān)聽的IP地址和端口,一般一個服務程序只監(jiān)聽某個端口的網絡連接。當有新的客戶端接入時,QTcpServer內部的incomingConnection()函數會創(chuàng)建一個與客戶端連接的QTcpSocket對象,然后發(fā)射信號newConnection()。在newConnection()信號的槽函數中,可以用nextPendingConnection()接受客戶端的連接,然后使用QTcpSocket與客戶端進行通信。【例11.5】編寫一個Qt應用程序,演示基于TCP協議的服務器端程序設計方法。(1)啟動QtCreator集成開發(fā)環(huán)境,創(chuàng)建一個名為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集成開發(fā)環(huán)境,創(chuàng)建一個名為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每次發(fā)送數據報都需要指定目標地址和端口。Qt中的UDP通信通過QUdpSocket類來實現。11.5.1QUdpSocket類與QTcpSocket一樣,QUdpSocket也是從QAbstractSocket類派生出來的,其繼承關系如圖11.10所示。除了繼承下來的函數之外,QUdpSocket還定義了一些特有的成員函數,如表11.9所示。11.5.2UDP單播UDP消息傳送有單播、廣播、組播三種模式,其示意圖如圖11.16所示?!纠?1.7】編寫一個Qt應用程序,演示基于UDP協議的網絡通信功能的實現方法。(1)啟動QtCreator集成開發(fā)環(huán)境,創(chuàng)建一個名為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多播地址接收多播數據報的所有主機構成了一個組,稱為多播組或組播組。所有的信息接收者都加入到一個組內,并且一旦加入之后,流向組地址的數據報立即開始向接收者傳輸,組中的所有成員都能接收到數據報。組中的成員是動態(tài)的,主機可以在任何時候加入和離開組播組?!纠?1.8】編寫一個Qt應用程序,演示基于UDP協議的網絡組播通信功能的實現方法。(1)啟動QtCreator集成開發(fā)環(huán)境,創(chuàng)建一個名為examp11_8的Qt應用程序,設置應用程序主窗口基類QWidget。(2)雙擊widget.ui界面文件打開QtDesigner界面設計工具,在應用程序主窗口中放置部件并使用布局管理器進行布局。主窗口中部件對象類型及名稱如圖11.22所示。(3)打開examp11_8.pro項目文件,添加QtNetwork模塊支持。如下所示。QT+=network(4)在Widget類中添加私有成員變量、成員函數和槽函數,其聲明代碼如下所示。(5)在Widget類的構造函數中添加代碼,并實現上述(4)中的函數功能。如下所示。(5)構建并運行程序。課后作業(yè)思政本章結束Qt6.2/C++程序設計與桌面應用開發(fā)21世紀高等學校計算機類課程創(chuàng)新規(guī)劃教材–微課視頻版教材目錄第1章初識Qt框架第2章Qt開發(fā)基礎第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控制臺程序并執(zhí)行dir命令的示例代碼。12.1.2QThread類QThread類直接繼承自QObject類,每個QThread對象代表了一個在應用程序中可以獨立控制的線程,這個線程與進程中的其他線程分享數據。表12.2給出了QThread類的部分非繼承成員函數及功能。下面是一段使用QThread類實現多線程的示例代碼。12.2進程進程(Process)是計算機中的程序關于數據集合上的一次運行活動,是正在運行的程序的實例。從理論角度來看,進程是對正在運行的程序過程的抽象;從實現角度來看,進程就是一種數據結構。進程清晰地刻畫了動態(tài)系統的內在規(guī)律,并有效地管理和調度進入計算機系統主存儲器運行的程序。12.2.1進程的啟動進程是一個“執(zhí)行中的程序”,所以,啟動進程就是開始運行一個程序。可以使用QProcess類的start()、startDetached()和execute()函數來啟動一個進程。下面是一個在Qt應用程序中打開/關閉Windows系統計算器的簡單實例?!纠?2.1】編寫一個Qt應用程序,在程序中運行Windows計算器。(1)打開QtCreator集成開發(fā)環(huán)境,創(chuàng)建一個基于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類,允許在本地設置中進行類似網絡的通信?!纠?2.2】編寫一個Qt應用程序,通過LocalServer/Socket方法來實現進程之間的通信。(1)打開QtCreator集成開發(fā)環(huán)境,創(chuàng)建2個基于QDialog類的Qt應用程序。項目名稱分別為examp12_1_server和examp12_1_client。前者表示服務器端程序,后者表示客戶端程序。(2)編寫服務器端程序代碼。下面只給出部分關鍵代碼,其他請參見教材源碼。(3)編寫客戶端程序代碼。下面只給出部分關鍵代碼,其他請參見教材源碼。(4)構建并運行程序。3、SharedMemory方法QtNetwork模塊中的跨平臺的QSharedMemory
共享內存類,提供對操作系統的共享內存的實現,它允許多個線程和進程安全訪問共享內存段。QSystemSemaphore也可以用來控制訪問由系統共享的資源以及進程之間的通信?!纠?2.3】編寫一個Qt應用程序,使用共享內存來實現進程之間的通信。(1)打開QtCreator集成開發(fā)環(huán)境,創(chuàng)建一個基于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級別,允許由一個進程發(fā)出的信號被連接到另一個進程的槽。該方法的實現,請參見Qt的示例程序D-BusChatExample和D-BusRemoteControlledCarExample5、QProcess方法跨平臺類QProcess能夠用于啟動外部程序作為子進程,并與它們進行通訊。它提供了用于監(jiān)測和控制該子進程狀態(tài)的API。另外,QProcess為從QIODevice繼承的子進程提供了輸入/輸出通道。該方法的實現,請參見上面12.1.1小節(jié)中的code_12_1_1示例項目。6、SessionManagement方法在Linux/X11平臺上,Qt提供了會話管理的支持。會話容許事件傳播到進程,例如,當檢測到關機時,進程和應用程序能夠執(zhí)行任何必須的操作,如保存打開的文檔等。12.3線程Qt對線程的支持是通過三個方面來實現的:一是提供了一組與平臺無關的線程類,二是提供了一個線程安全的事件發(fā)送方式,三是提供了跨線程的信號與槽的關聯。Qt對多線程操作的全面支持,使得開發(fā)可移植的Qt多線程應用程序變得非常容易,同時還可以充分發(fā)揮多處理器中各個內核的效用。12.3.1線程的運行在Qt的多線程應用程序中,通常使用QThread類提供的方法來對線程進行管理。一個QThread類的對象管理一個線程,默認情況下,線程是在QThread::run()函數中開始運行的,run()函數通過調用exec()啟動并運行Qt的事件循環(huán)。1、線程的創(chuàng)建在多線程編程中,將應用程序的線程稱為主線程,額外創(chuàng)建的線程稱為工作線程。工作線程可以通過兩種方法來創(chuàng)建:一種方法是自定義QThread類的子類,并重載run()函數;另一種方法是先創(chuàng)建工作對象,然后使用QObject::moveToThread()函數將工作對象嵌入到線程中。(1)使用QThread子類對象通過子類化QThread來創(chuàng)建工作線程,是Qt多線程編程中的常用方法。下面是一段示例代碼。(2)使用QObject::moveToThread()函數通過這種方法創(chuàng)建工作線程,首先需要創(chuàng)建一個工作者對象,將線程任務集中到這個對象中,然后使用QObject::moveToThread()函數完成工作線程的創(chuàng)建。示例如下。2、線程的啟動工作線程創(chuàng)建完成后,可以在外部創(chuàng)建該線程的實例,然后調用start()函數來開始執(zhí)行該線程,start()默認會調用run()函數。下面來看一個簡單的實例?!纠?2.4】編寫一個Qt應用程序,統計n個自然數中質數的個數。要求統計計算在單獨的線程中完成,主線程接收用戶輸入并顯示統計結果。(1)打開QtCreator集成開發(fā)環(huán)境,創(chuàng)建一個基于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)步中創(chuàng)建的2個槽函數添加代碼,實現相應的功能。如下所示。(6)構建并運行程序。程序運行后,輸入不同的n值,并單擊“計算”按鈕進行測試,結果如圖12.10所示。該程序子線程中的計算結果是直接在控制臺輸出的,如果要將計算結果傳遞到主線程中,就需要了解線程間通信的基本方法。12.3.2線程間通信線程間的通信一般通過兩種方法來實現,即成員變量方法和自定義信號方法。成員變量方法就是通過線程對象的成員變量來返回線程數據;自定義信號方法通過在線程類中定義信號,利用信號參數來傳遞線程數據。1、成員變量方法由于線程任務是在run()函數中完成的,而run()函數又屬于線程類的成員函數,所以可以通過線程類的成員變量來存儲run()函數中的相關數據?!纠?2.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的信號與槽通訊機制中,對象在發(fā)射信號的時候是可以附帶傳送一些參數的。所以,可以通過在線程類中定義信號,利用信號參數來傳遞線程數據?!纠?2.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
又稱為互斥鎖,用于保護共享資源(如對象、數據結構和代碼段等),它們能夠保證多線程程序中在同一時刻只有一個線程訪問共享資源?!纠?2.7】編寫一個Qt應用程序,示例使用互斥量保護共享資源。(1)打開QtCreator集成開發(fā)環(huán)境,創(chuàng)建一個基于QWidget類的Qt應用程序,項目名稱為examp12_7。(2)在項目中添加一個名為TestData的C++類,并在該類中定義2個靜態(tài)成員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),這個結果是執(zhí)行了語句6、語句2和語句3后得到的。也就是說,在線程2還沒有對共享數據TestData::sharedNumber修改(語句7還沒有執(zhí)行)完成的時候,線程1便對該共享數據進行了修改。很顯然這個計算結果是不符合程序設計者的初衷的。接著,測試使用互斥鎖后程序的運行情況。取消語句1、語句5和語句9的注釋,重新構建并運行程序,結果如圖12.15所示。從結果可以看到,使用互斥鎖以后,線程1就不能在線程2訪問共享數據的時候對其進行操作了。這樣有效保護了程序
溫馨提示
- 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請下載最新的WinRAR軟件解壓。
- 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯系上傳者。文件的所有權益歸上傳用戶所有。
- 3. 本站RAR壓縮包中若帶圖紙,網頁內容里面會有圖紙預覽,若沒有圖紙預覽就沒有圖紙。
- 4. 未經權益所有人同意不得將文件中的內容挪作商業(yè)或盈利用途。
- 5. 人人文庫網僅提供信息存儲空間,僅對用戶上傳內容的表現方式做保護處理,對用戶上傳分享的文檔內容本身不做任何修改或編輯,并不能對任何下載內容負責。
- 6. 下載文件中如有侵權或不適當內容,請與我們聯系,我們立即糾正。
- 7. 本站不保證下載資源的準確性、安全性和完整性, 同時也不承擔用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。
最新文檔
- 二零二五年度食品出口銷售合同標準范本3篇
- 二零二五年節(jié)能照明設備銷售合作協議3篇
- 二零二五版建筑廢棄物資源化利用與處理合同3篇
- 二零二五年度汽車買賣及售后服務合同范本3篇
- 二零二五版新型采購監(jiān)控設備采購與維護服務協議3篇
- 2025年國有企業(yè)廠長任期目標責任書及薪酬激勵機制合同3篇
- 二零二五年度高空橋梁檢修作業(yè)安全協議書2篇
- 二零二五版技術專利權轉讓與產業(yè)鏈協同創(chuàng)新與市場拓展服務協議3篇
- 2025年度餐廳裝修設計與施工合同2篇
- 2瓷磚銷售合同2024年版
- mil-std-1916抽樣標準(中文版)
- 2024年安徽省合肥市瑤海區(qū)中考語文一模試卷
- 單位車輛變更名稱的委托書
- 粉塵外協單位清理協議書
- 2023年12月首都醫(yī)科大學附屬北京中醫(yī)醫(yī)院面向應屆生招考聘用筆試近6年高頻考題難、易錯點薈萃答案帶詳解附后
- 茶室經營方案
- 軍隊文職崗位述職報告
- 小學數學六年級解方程練習300題及答案
- 電抗器噪聲控制與減振技術
- 中醫(yī)健康宣教手冊
- 2024年江蘇揚州市高郵市國有企業(yè)招聘筆試參考題庫附帶答案詳解
評論
0/150
提交評論