Qt5开发及实例V2.0-第十章Qt网络与通信

news2024/11/19 20:30:42

Qt5开发及实例V2.0-第十章Qt网络与通信

  • 第10章 Qt 5网络与通信
    • 10.1 获取本机网络信息
    • 10.2 基于UDP的网络广播程序
      • 10.2.1 UDP协议工作原理
      • 10.2.2 UDP 编程模型
      • 10.2.3 【实例】:UDP服务器编程
      • 10.2.4 【实例】:UDP客户端编程
    • 10.3 基于TCP的网络聊天室程序
      • 10.3.1 TCP协议工作原理
      • 10.3.2 TCP编程模型
      • 10.3.3 【实例】:TCP服务器编程
      • 10.3.4 【实例】:TCP客户端编程
    • 10.4 Qt网络应用开发初步
      • 10.4.1 【实例】:简单网页浏览器
      • 10.4.2 文件下载实例
  • 本章相关例程源码下载
    • 1.Qt5开发及实例_CH1001.rar 下载
    • 2.Qt5开发及实例_CH1002.rar 下载
    • 3.Qt5开发及实例_CH1003.rar 下载
    • 4.Qt5开发及实例_CH1004.rar 下载
    • 5.Qt5开发及实例_CH1005.rar 下载
    • 6.Qt5开发及实例_CH1006.rar 下载

第10章 Qt 5网络与通信

10.1 获取本机网络信息

【例】(简单)(CH1001)获得本机的网络信息。
实现步骤如下。
(1)头文件“networkinformation.h”的具体代码如下:

#include <QWidget>
#include <QLabel>
#include <QPushButton>
#include <QLineEdit>
#include <QGridLayout>
#include <QMessageBox>
class NetworkInformation : public QWidget
{
    Q_OBJECT
public:
    NetworkInformation(QWidget *parent = 0);
    ~NetworkInformation();
private:
    QLabel *hostLabel;
    QLineEdit *LineEditLocalHostName;
    QLabel *ipLabel;
    QLineEdit *LineEditAddress;
    QPushButton *detailBtn;
    QGridLayout *mainLayout;
};

(2)源文件“networkinformation.cpp”的具体代码如下:

#include "networkinformation.h"
NetworkInformation::NetworkInformation(QWidget *parent)
    : QWidget(parent)
{
    hostLabel = new QLabel(tr("主机名:"));
    LineEditLocalHostName = new QLineEdit;
    ipLabel = new QLabel(tr("IP 地址:"));
    LineEditAddress = new QLineEdit;
    detailBtn = new QPushButton(tr("详细"));
    mainLayout = new QGridLayout(this);
    mainLayout->addWidget(hostLabel,0,0);
    mainLayout->addWidget(LineEditLocalHostName,0,1);
    mainLayout->addWidget(ipLabel,1,0);
    mainLayout->addWidget(LineEditAddress,1,1);
    mainLayout->addWidget(detailBtn,2,0,1,2);
}

此时,运行结果如图10.1所示。
在这里插入图片描述
以上完成了界面,下面开始真正实现获得本机网络信息的内容。
(1)在文件“NetworkInformation.pro”中添加如下代码:

QT += network

(2)在头文件“networkinformation.h”中添加如下代码:

#include <QHostInfo>
#include <QNetworkInterface>
public:
    void getHostInformation();
public slots:
    void slotDetail();

(3)在源文件“networkinformation.cpp”中添加代码。其中,在构造函数的最后添加:

getHostInformation();
connect(detailBtn,SIGNAL(clicked()),this,SLOT(slotDetail()));

getHostInformation()函数用于获得主机信息。具体实现代码如下:

void NetworkInformation::getHostInformation()
{
    QString localHostName = QHostInfo::localHostName();	//(a)
    LineEditLocalHostName->setText(localHostName);
    QHostInfo hostInfo = QHostInfo::fromName(localHostName);	//(b)
	//获得主机的IP地址列表
    QList<QHostAddress> listAddress = hostInfo.addresses();
    if(!listAddress.isEmpty())				//(c)
    {
        LineEditAddress->setText(listAddress.at(2).toString());
    }
}

其中,
(a) QString localHostName = QHostInfo::localHostName():获得本机主机名。QHostInfo提供了一系列有关网络信息的静态函数,可以根据主机名获得分配的IP地址,也可以根据IP地址获得相应的主机名。
(b) QHostInfo hostInfo = QHostInfo::fromName(localHostName):根据主机名获得相关主机信息,包括IP地址等。QHostInfo::fromName()函数通过主机名查找IP地址信息。
© if(!listAddress.isEmpty()){…}:获得的主机IP地址列表可能为空。在不为空的情况下使用第一个IP地址。
slotDetail()函数获得与网络接口相关的信息,具体实现代码。

(4)运行结果如图10.2所示。
单击“详细”按钮后,弹出如图10.3所示的信息窗口。
在这里插入图片描述

10.2 基于UDP的网络广播程序

适合应用的情况有以下几种:
 网络数据大多为短消息。
 拥有大量客户端。
 对数据安全性无特殊要求。
 网络负担非常重,但对响应速度要求高。

10.2.1 UDP协议工作原理

如图10.4所示,UDP客户端向UDP服务器发送一定长度的请求报文,报文大小的限制与各系统的协议实现有关,但不得超过其下层IP协议规定的64KB;UDP服务器同样以报文形式做出响应。
在这里插入图片描述

10.2.2 UDP 编程模型

下面介绍基于UDP协议的经典编程模型,程序编写的通用流程如图10.5所示。
在这里插入图片描述

10.2.3 【实例】:UDP服务器编程

【例】(简单)(CH1002)服务器端的编程。
(1)在头文件“udpserver.h”中声明了需要的各种控件,其具体代码如下:

#include <QDialog>
#include <QLabel>
#include <QLineEdit>
#include <QPushButton>
#include <QVBoxLayout>
class UdpServer : public QDialog
{
    Q_OBJECT
public:
    UdpServer(QWidget *parent=0,Qt::WindowFlags f=0);
    ~UdpServer();
private:
    QLabel *TimerLabel;
    QLineEdit *TextLineEdit;
    QPushButton *StartBtn;
    QVBoxLayout *mainLayout;
};

(2)源文件“udpserver.cpp”的具体代码如下:

#include "udpserver.h"
UdpServer::UdpServer(QWidget *parent,Qt::WindowFlags f)
    : QDialog(parent,f)
{
    setWindowTitle(tr("UDP Server"));		//设置窗体的标题
	/* 初始化各个控件 */
    TimerLabel = new QLabel(tr("计时器:"),this);
    TextLineEdit = new QLineEdit(this);
    StartBtn = new QPushButton(tr("开始"),this);
	/* 设置布局 */
    mainLayout = new QVBoxLayout(this);
    mainLayout->addWidget(TimerLabel);
    mainLayout->addWidget(TextLineEdit);
    mainLayout->addWidget(StartBtn);
}

(3)服务器的界面运行外观如图10.6所示。
在这里插入图片描述

以上只是完成了服务器界面的实现,下面完成它的广播功能。
实现步骤如下。
(1)在“UdpServer.pro”中添加如下语句:

QT += network

(2)在头文件“udpserver.h”中添加需要的槽函数,其具体代码如下:

#include <QUdpSocket>
#include <QTimer>
public slots:
    	void StartBtnClicked();
    	void timeout();
private:
	int port;
    	bool isStarted;
    	QUdpSocket *udpSocket;
    	QTimer *timer;

(3)在源文件“udpserver.cpp”中添加声明:

#include <QHostAddress>

其中,在构造函数中添加如下代码:

connect(StartBtn,SIGNAL(clicked()),this,SLOT(StartBtnClicked()));

port = 5555; //设置UDP的端口号参数,服务器定时向此端口发送广播信息

isStarted = false;
udpSocket = new QUdpSocket(this);
timer = new QTimer(this);		//创建一个QUdpSocket
//定时发送广播信息
connect(timer,SIGNAL(timeout()),this,SLOT(timeout()));

StartBtnClicked()函数的具体代码如下:

void UdpServer::StartBtnClicked()
{
    if(!isStarted)
    {
        StartBtn->setText(tr("停止"));
        timer->start(1000);
        isStarted =true;
    }
    else
    {
        StartBtn->setText(tr("开始"));
        isStarted = false;
        timer->stop();
    }
}

timeout()函数完成了向端口发送广播信息的功能,其具体代码如下:

void UdpServer::timeout()
{
    QString msg = TextLineEdit->text();
    int length=0;
    if(msg=="")
    {
       return;
    }
    if((length=udpSocket->writeDatagram(msg.toLatin1(),
    msg.length(),QHostAddress::Broadcast,port))!=msg.length())
    {
        return;
    }
}

10.2.4 【实例】:UDP客户端编程

【例】(简单)(CH1003)客户端的编程。
(1)在头文件“udpclient.h”中声明了需要的各种控件,其具体代码如下:

#include <QDialog>
#include <QVBoxLayout>
#include <QTextEdit>
#include <QPushButton>
class UdpClient : public QDialog
{
    Q_OBJECT
public:
    UdpClient(QWidget *parent = 0,Qt::WindowFlags f=0);
    ~UdpClient();
private:
    QTextEdit *ReceiveTextEdit;
    QPushButton *CloseBtn;
    QVBoxLayout *mainLayout;
};

(2)源文件“udpclient.cpp”的具体代码如下:

#include "udpclient.h"
UdpClient::UdpClient(QWidget *parent, Qt::WindowFlags f)
    : QDialog(parent,f)
{
    setWindowTitle(tr("UDP Client"));		//设置窗体的标题
	/* 初始化各个控件 */
    ReceiveTextEdit = new QTextEdit(this);
    CloseBtn = new QPushButton(tr("Close"),this);
	/* 设置布局 */
    mainLayout=new QVBoxLayout(this);
    mainLayout->addWidget(ReceiveTextEdit);
    mainLayout->addWidget(CloseBtn);
}

(3)客户端的界面运行外观如图10.7所示。
在这里插入图片描述
以上只是完成了客户端界面的实现,下面完成它的数据接收和显示的功能。
实现步骤如下。
(1)在“UdpClient.pro”中添加如下语句:

QT += network

(2)在头文件“udpclient.h”中添加以下代码:

#include <QUdpSocket>
public slots:
    	void CloseBtnClicked();
    	void dataReceived();
private:
	int port;
    	QUdpSocket *udpSocket;

(3)在源文件“udpclient.cpp”中添加如下声明:

#include <QMessageBox>
#include <QHostAddress>

其中,在构造函数中添加的代码如下:

connect(CloseBtn,SIGNAL(clicked()),this,SLOT(CloseBtnClicked()));
port =5555;			//设置UDP的端口号参数,指定在此端口上监听数据
udpSocket = new QUdpSocket(this);		//创建一个QUdpSocket
connect(udpSocket,SIGNAL(readyRead()),this,SLOT(dataReceived()));
						//(a)
bool result=udpSocket->bind(port);		//绑定到指定的端口上
if(!result)
{
    QMessageBox::information(this,tr("error"),tr("udp socket create error!"));
    return;
}

CloseBtnClicked()函数的具体内容如下:

void UdpClient::CloseBtnClicked()
{
    close();
}

dataReceived()函数响应QUdpSocket的readyRead()信号,一旦UdpSocket对象中有数据可读时,即通过readDatagram()方法将数据读出并显示。其具体代码如下:

void UdpClient::dataReceived()
{
    while(udpSocket->hasPendingDatagrams())		//(a)
    {
        QByteArray datagram;
        datagram.resize(udpSocket->pendingDatagramSize());
        udpSocket->readDatagram(datagram.data(),datagram.size());//(b)
        QString msg=datagram.data();
        ReceiveTextEdit->insertPlainText(msg);			//显示数据内容
    }
}

同时运行UdpServer与UdpClient工程,首先在服务器界面文本框中输入“hello!”,然后单击“开始”按钮,按钮文本变为“停止”,客户端就开始不断地收到“hello!”字符消息并显示在文本区,当单击服务器的“停止”按钮后,按钮文本又变回“开始”,客户端也就停止了字符的显示,再次单击服务器的“开始”按钮,客户端又继续接收并显示……如此循环往复,效果如图10.8所示。
在这里插入图片描述

10.3 基于TCP的网络聊天室程序

TCP协议与UDP协议的差别见表10.1。
在这里插入图片描述

10.3.1 TCP协议工作原理

如图10.9所示,TCP协议能够为应用程序提供可靠的通信连接,使一台计算机发出的字节流无差错地送达网络上的其他计算机。
在这里插入图片描述

10.3.2 TCP编程模型

下面介绍基于TCP协议的经典编程模型,程序编写的流程如图10.10所示。
在这里插入图片描述

10.3.3 【实例】:TCP服务器编程

【例】(难度中等)(CH1003)服务器端的编程。
建立工程TcpServer.pro,文件代码如下。
(1)头文件“tcpserver.h”中声明了需要的各种控件,TcpServer继承自QDialog,实现了服务器端的对话框显示与控制。其具体代码如下:

#include <QDialog>
#include <QListWidget>
#include <QLabel>
#include <QLineEdit>
#include <QPushButton>
#include <QGridLayout>
class TcpServer : public QDialog
{
    Q_OBJECT
public:
    TcpServer(QWidget *parent = 0,Qt::WindowFlags f=0);
    ~TcpServer();
private:
    QListWidget *ContentListWidget;
    QLabel *PortLabel;
    QLineEdit *PortLineEdit;
    QPushButton *CreateBtn;
    QGridLayout *mainLayout;
};

(2)在源文件“tcpserver.cpp”中,TcpServer类的构造函数主要实现窗体各控件的创建、布局等,其具体代码如下:

#include "tcpserver.h"
TcpServer::TcpServer(QWidget *parent,Qt::WindowFlags f)
    : QDialog(parent,f)
{
    setWindowTitle(tr("TCP Server"));
    ContentListWidget = new QListWidget;
    PortLabel = new QLabel(tr("端口:"));
    PortLineEdit = new QLineEdit;
    CreateBtn = new QPushButton(tr("创建聊天室"));
    mainLayout = new QGridLayout(this);
    mainLayout->addWidget(ContentListWidget,0,0,1,2);
    mainLayout->addWidget(PortLabel,1,0);
    mainLayout->addWidget(PortLineEdit,1,1);
    mainLayout->addWidget(CreateBtn,2,0,1,2);
}

(3)服务器端的界面运行外观如图10.11所示。
在这里插入图片描述
以上完成了服务器的界面设计,下面将详细完成聊天室的服务器端功能。
(1)在工程文件“TcpServer.pro”中添加如下语句:

QT += network

(2)在工程“TcpServer.pro”中添加C++类文件“tcpclientsocket.h”及“tcpclientsocket.cpp”,TcpClientSocket继承自QTcpSocket,创建一个TCP套接字,以便在服务器端实现与客户端程序的通信。
头文件“tcpclientsocket.h”的具体代码如下:

#include <QTcpSocket>
#include <QObject>
class TcpClientSocket : public QTcpSocket
{
    Q_OBJECT                //添加宏(Q_OBJECT)是为了实现信号与槽的通信
public:
    TcpClientSocket(QObject *parent=0);
signals:
    void updateClients(QString,int);
    void disconnected(int);
protected slots:
    void dataReceived();
    void slotDisconnected();
};

(3)在源文件“tcpclientsocket.cpp”中,构造函数(TcpClientSocket)的内容如下(它指定了信号与槽的连接关系):

#include "tcpclientsocket.h"
TcpClientSocket::TcpClientSocket(QObject *parent)
{
    connect(this,SIGNAL(readyRead()),this,SLOT(dataReceived())); //(a)
    connect(this,SIGNAL(disconnected()),this,SLOT(slotDisconnected())); //(b)
}

在源文件“tcpclientsocket.cpp”中,dataReceived()函数的具体代码如下:

void TcpClientSocket::dataReceived()
{
    while(bytesAvailable()>0)
    {
        int length = bytesAvailable();
        char buf[1024];
        read(buf,length);
        QString msg=buf;
        emit updateClients(msg,length);
    }
}

在源文件“tcpclientsocket.cpp”中,槽函数slotDisconnected()的具体代码如下:

void TcpClientSocket::slotDisconnected()
{
    emit disconnected(this->socketDescriptor());
}

(4)在工程“TcpServer.pro”中添加C++类文件“server.h”及“server.cpp”,Server继承自QTcpServer,实现一个TCP协议的服务器。利用QTcpServer,开发者可以监听到指定端口的TCP连接。其具体代码如下:

#include <QTcpServer>
#include <QObject>
#include "tcpclientsocket.h"	//包含TCP的套接字
class Server : public QTcpServer
{
    Q_OBJECT                  	//添加宏(Q_OBJECT)是为了实现信号与槽的通信
public:
    Server(QObject *parent=0,int port=0);
    QList<TcpClientSocket*> tcpClientSocketList;
signals:
    void updateServer(QString,int);
public slots:
    void updateClients(QString,int);
    void slotDisconnected(int);
protected:
    void incomingConnection(int socketDescriptor);
};

(5)在源文件“server.cpp”中,构造函数(Server)的具体内容如下:

#include "server.h"
Server::Server(QObject *parent,int port):QTcpServer(parent)
{
    listen(QHostAddress::Any,port);
}

其中,listen(QHostAddress::Any,port)在指定的端口对任意地址进行监听。

在源文件“server.cpp”中,当出现一个新的连接时,QTcpSever触发incomingConnection()函数,参数socketDescriptor指定了连接的Socket描述符,其具体代码如下:

void Server::incomingConnection(int socketDescriptor)
{
    TcpClientSocket *tcpClientSocket=new TcpClientSocket(this);
							//(a)
    connect(tcpClientSocket,SIGNAL(updateClients(QString,int)),
            this,SLOT(updateClients(QString,int)));		//(b)
    connect(tcpClientSocket,SIGNAL(disconnected(int)),this,
            SLOT(slotDisconnected(int)));			//(c)
    tcpClientSocket->setSocketDescriptor(socketDescriptor);
							//(d)
    tcpClientSocketList.append(tcpClientSocket);		//(e)
}

在源文件“server.cpp”中,updateClients()函数将任意客户端发来的信息进行广播,保证聊天室的所有客户均能看到其他人的发言。其具体代码如下:

void Server::updateClients(QString msg,int length)
{
    emit updateServer(msg,length);				//(a)
    for(int i=0;i<tcpClientSocketList.count();i++)			//(b)
    {
        QTcpSocket *item = tcpClientSocketList.at(i);
        if(item->write(msg.toLatin1(),length)!=length)
        {
            continue;
        }
    }
}

在源文件“server.cpp”中,slotDisconnected()函数实现从tcpClientSocketList列表中将断开连接的TcpClientSocket对象删除的功能。其具体代码如下:

void Server::slotDisconnected(int descriptor)
{
    for(int i=0;i<tcpClientSocketList.count();i++)
    {
        QTcpSocket *item = tcpClientSocketList.at(i);
        if(item->socketDescriptor()==descriptor)
        {
            tcpClientSocketList.removeAt(i);
            return;
        }
    }
    return;
}

(6)在头文件“tcpserver.h”中添加如下内容:

#include "server.h"
private:
	int port;
    	Server *server;
public slots:
    	void slotCreateServer();
    	void updateServer(QString,int);

(7)在源文件“tcpserver.cpp”中,构造函数中添加如下代码:

port=8010;
PortLineEdit->setText(QString::number(port));
connect(CreateBtn,SIGNAL(clicked()),this,SLOT(slotCreateServer()));

其中,槽函数slotCreateServer()用于创建一个TCP服务器,具体内容如下:

void TcpServer::slotCreateServer()
{
    server = new Server(this,port);		//创建一个Server对象
    connect(server,SIGNAL(updateServer(QString,int)),this,
            SLOT(updateServer(QString,int)));	//(a)
    CreateBtn->setEnabled(false);
}

槽函数updateServer()用于更新服务器上的信息显示,具体内容如下:

void TcpServer::updateServer(QString msg,int length)
{
    ContentListWidget->addItem(msg.left(length));
}

(8)此时工程中添加了很多文件,工程文件中的内容已经被改变,需重新在工程文件“TcpServer.pro”中添加:

QT += network

此时运行服务器端工程“TcpServer.pro”编译通过。单击“创建聊天室”按钮,便开通了一个TCP聊天室的服务器,如图10.12所示。
在这里插入图片描述

10.3.4 【实例】:TCP客户端编程

【例】(难度中等)(CH1004)客户端的编程。
建立工程“TcpClient.pro”,文件代码如下。
(1)头文件“tcpclient.h”中,TcpClient类继承自QDialog类,声明了需要的各种控件,其具体代码。
(2)源文件“tcpclient.cpp”的具体代码。
(3)客户端的界面运行外观如图10.13所示。
在这里插入图片描述

以上完成了客户端的界面设计,下面将完成客户端的真正聊天功能。
(1)在客户端工程文件“TcpClient.pro”中添加如下语句:

QT += network

(2)在头文件“tcpclient.h”中添加如下代码:

#include <QHostAddress>
#include <QTcpSocket>
private:
	bool status;
    	int port;
    	QHostAddress *serverIP;
    	QString userName;
    	QTcpSocket *tcpSocket;
public slots:
    	void slotEnter();
    	void slotConnected();
    	void slotDisconnected();
    	void dataReceived();
    	void slotSend();

(3)在源文件“tcpclient.cpp”中,添加头文件:

#include <QMessageBox>
#include <QHostInfo>

在其构造函数中添加如下代码:

status = false;
    port = 8010;
    portLineEdit->setText(QString::number(port));
    serverIP =new QHostAddress();
    connect(enterBtn,SIGNAL(clicked()),this,SLOT(slotEnter()));
    connect(sendBtn,SIGNAL(clicked()),this,SLOT(slotSend()));
    sendBtn->setEnabled(false);

在以上代码中,槽函数slotEnter()实现了进入和离开聊天室的功能。具体代码。

在源文件“tcpclient.cpp”中,槽函数slotConnected()为connected()信号的响应槽,当与服务器连接成功后,客户端构造一条进入聊天室的消息,并通知服务器。其具体代码如下:

void TcpClient::slotConnected()
{
    sendBtn->setEnabled(true);
    enterBtn->setText(tr("离开"));
    int length=0;
    QString msg=userName+tr(":Enter Chat Room");
    if((length=tcpSocket->write(msg.toLatin1(),msg. length()))!=msg. length())
    {
        return;
    }
}

在源文件“tcpclient.cpp”中,槽函数slotSend()的具体代码如下:

void TcpClient::slotSend()
{
    if(sendLineEdit->text()=="")
    {
        	return;
    }
    QString msg=userName+":"+sendLineEdit->text();
    tcpSocket->write(msg.toLatin1(),msg.length());
    sendLineEdit->clear();
}

在源文件“tcpclient.cpp”中,槽函数slotDisconnected()的具体内容如下:

void TcpClient::slotDisconnected()
{
    sendBtn->setEnabled(false);
    enterBtn->setText(tr("进入聊天室"));
}

源文件“tcpclient.cpp”的dataReceived()函数,当有数据到来时,触发此函数,从套接字中将有效数据取出并显示,其代码如下:

void TcpClient::dataReceived()
{
    while(tcpSocket->bytesAvailable()>0)
    {
        QByteArray datagram;
        datagram.resize(tcpSocket->bytesAvailable());
        tcpSocket->read(datagram.data(),datagram.size());
        QString msg=datagram.data();
        contentListWidget->addItem(msg.left(datagram.size()));
    }
}

(4)此时运行客户端“TcpClient.pro”工程,结果如图10.14所示。
在这里插入图片描述
最后,同时运行服务器和客户端程序,运行的效果如图10.15所示,这里演示的是系统中登录了两个用户的状态。
在这里插入图片描述

10.4 Qt网络应用开发初步

应用层的网络协议(如HTTP/FTP/SMTP等)简称“应用协议”,它们运行在TCP/UDP之上,如图10.16所示。
在这里插入图片描述

10.4.1 【实例】:简单网页浏览器

【例】(难度中等)(CH1006)简单网页浏览器。
实现步骤如下。
新建Qt Widgets Application,名称为“myHTTP”,类名为“MainWindow”,基类保持“QMainWindow”不变。完成后先在“myHTTP.pro”文件中添加语句“QT+=network”,并保存该文件。进入设计模式,向界面上拖入一个Text Browser,然后进入“mainwindow.h”文件,首先添加类的前置声明:

class QNetworkReply;
class QNetworkAccessManager;

然后添加一个私有对象定义:

QNetworkAccessManager *manager;

下面再添加一个私有槽的声明:

private slots:
    void replyFinished(QNetworkReply *);

现在到“mainwindow.cpp”文件中,首先添加头文件:

#include <QtNetwork>

然后在构造函数中添加如下代码:

manager = new QNetworkAccessManager(this);
connect(manager,SIGNAL(finished(QNetworkReply*)),this
				,SLOT(replyFinished(QNetworkReply*)));
manager->get(QNetworkRequest(QUrl("http://www.baidu.com")));

下面添加槽的定义:

void MainWindow::replyFinished(QNetworkReply *reply)
{
    QString all = reply->readAll();
    ui->textBrowser->setText(all);
    reply->deleteLater();
}

运行程序,显示出“百度搜索”首页,效果如图10.17所示。
在这里插入图片描述

10.4.2 文件下载实例

下面在网页浏览实例的基础上,实现一般页面文件的下载,并且显示下载进度。进入设计模式,向界面上拖入Label、Line Edit、Progress Bar和Push Button等部件,最终效果如图10.18所示。
在这里插入图片描述
下面在“mainwindow.h”文件中,首先添加头文件和类的前置声明:

#include <QUrl>
class QFile;

其次添加如下私有槽声明:

void httpFinished();
void httpReadyRead();
void updateDataReadProgress(qint64,qint64);

然后再添加一个public函数声明:

void startRequest(QUrl url);

再次添加几个私有对象定义:

QNetworkReply *reply;
QUrl url;
QFile *file;

下面在“mainwindow.cpp”文件中,在构造函数中添加:

ui->progressBar->hide();

这里开始将进度条隐藏了,因此在没有下载文件时是不显示进度条的。
接下来添加几个新函数,首先添加网络请求函数的实现:

void MainWindow::startRequest(QUrl url)
{
    reply = manager->get(QNetworkRequest(url));
    connect(reply,SIGNAL(readyRead()),this,SLOT(httpReadyRead()));
    connect(reply,SIGNAL(downloadProgress(qint64,qint64)),this
			,SLOT(updateDataReadProgress(qint64,qint64)));
    connect(reply,SIGNAL(finished()),this,SLOT(httpFinished()));
}

下面添加几个槽的定义:

void MainWindow::httpReadyRead()
{
    if(file)file->write(reply->readAll());
}

这里首先判断是否创建了文件。如果是,则读取返回的所有数据,然后写入文件中。该文件是在后面的“下载”按钮的单击信号的槽中创建并打开的。

void MainWindow::updateDataReadProgress(qint64 bytesRead, qint64 totalBytes)
{
    ui->progressBar->setMaximum(totalBytes);
    ui->progressBar->setValue(bytesRead);
}

这里设置了进度条的最大值和当前值。

void MainWindow::httpFinished()
{
    ui->progressBar->hide();
    file->flush();
    file->close();
    reply->deleteLater();
    reply = 0;
    delete file;
    file = 0;
}

进入设计模式,进入“下载”按钮的单击信号的槽,添加如下代码:

void MainWindow::on_pushButton_clicked()
{
    url = ui->lineEdit->text();
    QFileInfo info(url.path());
    QString fileName(info.fileName());
    file = new QFile(fileName);
    if(!file->open(QIODevice::WriteOnly))
    {
        qDebug()<<"file open error";
        delete file;
        file = 0;
        return;
    }
    startRequest(url);
    ui->progressBar->setValue(0);
    ui->progressBar->show();
}

可以使用如下URL地址(地址会有变化,读者请根据实际情况测试程序):
http://sqdownb.onlinedown.net/down/WeChatSetup.zip
下载过程中,进度条出现并动态变化,如图10.19所示。下载完成后可在项目工程所在路径的D:\Qt\CH10\CH1006\build-myHTTP-Desktop_Qt_5_8_0_MinGW_32bit-Debug下找到该文件。
在这里插入图片描述



本章相关例程源码下载

1.Qt5开发及实例_CH1001.rar 下载

Qt5开发及实例_CH1001.rar

2.Qt5开发及实例_CH1002.rar 下载

Qt5开发及实例_CH1002.rar

3.Qt5开发及实例_CH1003.rar 下载

Qt5开发及实例_CH1003.rar

4.Qt5开发及实例_CH1004.rar 下载

Qt5开发及实例_CH1004.rar

5.Qt5开发及实例_CH1005.rar 下载

Qt5开发及实例_CH1005.rar

6.Qt5开发及实例_CH1006.rar 下载

Qt5开发及实例_CH1006.rar

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1046519.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

力扣(LeetCode)1333. 餐厅过滤器(C++)

优先队列 请读者读题&#xff0c;应该会发现两个重点&#xff1a;过滤器和排序。大家有没有发现这个效果&#xff0c;有点像xx点评: 大家选店一般在口味/距离/价格能接受的前提下&#xff0c;选评分最高的那家店hh&#xff0c;这就是过滤器的效果。排序是说&#xff0c;对满足…

【SQL】统一训练平台数据库实践--20230927

储存过程vlookup_peopledata_csodtraining 默认导出用今天批次的数据进行join on&#xff0c;先删除过渡表的资料&#xff0c;再将查询结果放在过渡表中。 BEGINDECLARE startdate varchar(50);SET startdate date_format(NOW(),%Y%m%d);DELETE FROM season.csod_data2;INSE…

50KW可编程水冷负载箱的工作原理

可编程水冷负载箱内部配备了水冷系统&#xff0c;包括水泵、水冷片和水冷风扇。水泵将冷却液&#xff08;通常是水&#xff09;循环输送到负载器件上&#xff0c;通过水冷片和水冷风扇将热量散发出去&#xff0c;以保持负载器件的温度在可控范围内。通过编程控制负载器件的工作…

【钻石OA】1区SCI,无需版面费,仅2个月录用!

重 点 本期推荐 本期小编给大家推荐的是无需版面费的1区农林科学类SCI&#xff08;钻石OA&#xff09;。 目前进展顺利&#xff0c;在WOS数据库中各项指标表现良好&#xff0c;且无预警记录。 领域符合录用率高&#xff0c;1区SCI最快2个月录用&#xff01; 期刊官网系统提…

uni-app 之 短信验证码登录

uni-app 之 短信验证码登录 image.png image.png <template><view style"width: 100%; display: flex; flex-direction:column; align-items:center;"><view style"width: 300px; margin-top: 100px;"><!-- // --><!-- 1&#…

今天给大家介绍一篇基于java的养老院管理系统的设计与实现

项目描述 临近学期结束&#xff0c;还是毕业设计&#xff0c;你还在做java程序网络编程&#xff0c;期末作业&#xff0c;老师的作业要求觉得大了吗?不知道毕业设计该怎么办?网页功能的数量是否太多?没有合适的类型或系统?等等。今天给大家介绍一篇基于java的养老院管理系…

服务网关Gateway_微服务中的应用

没有服务网关 问题&#xff1a; 地址太多安全性管理问题 为什么要使用服务网关 网关是微服务架构中不可或缺的部分。使用网关后&#xff0c;客户端和微服务之间的网络结构如下。 注意&#xff1a; 网关统一向外部系统&#xff08;如访问者、服务&#xff09;提供REST API。在Sp…

Android 编译插桩操纵字节码

本文讲解如何编译插桩操纵字节码。 就使用 ASM 来实现简单的编译插桩效果&#xff0c;通过插桩实现在每一个 Activity 打开时输出相应的 log 日志。实现思路 过程主要包含两步&#xff1a; 1、遍历项目中所有的 .class 文件​ 如何找到项目中编译生成的所有 .class 文件&#…

Win/Mac版Scitools Understand教育版申请

这里写目录标题 前言教育版申请流程教育账号申请 前言 上篇文章为大家介绍了Scitools Understand软件&#xff0c;通过领取的反馈来看有很多朋友都想用这个软件&#xff0c;但是我的网盘里只存了windows的pojie版&#xff0c;没有mac版的&#xff0c;我没有去网上找相关的资源…

支持笔记本电脑直插直充,TOWE 65W智能快充PDU超级插座

电源插排在我们的生活中是必不可少的电器配件。今天&#xff0c;我们日常生活中所使用的电子设备越来越多&#xff0c;无论是手机、平板、笔记本电脑还是各种家用电器&#xff0c;都需要电源来驱动。虽然相对于其他电器来说&#xff0c;插排结构比较简单&#xff0c;但现代家庭…

LabVIEW开发具有栅极感应漏极电流的电荷泵

LabVIEW开发具有栅极感应漏极电流的电荷泵 由操作压力引起的接口陷阱一直是一个长期问题&#xff0c;因为它们会降低栅极电介质的质量&#xff0c;引起器件参数的不必要变化&#xff0c;例如导通状态电流、亚阈值摆幅、阈值电压和跨导。因此&#xff0c;表征界面疏水阀对于确保…

broadcast自动扩展

broadcast&#xff1a; 1、能够进行维度扩展&#xff0c;是自动的2、在扩展的时候不需要拷贝数据要点&#xff1a; - 从最小的维度开始匹配&#xff0c;如果前面没有维度了&#xff0c;在前面插入一个新的维度。- 插入的新维度size是1&#xff0c;再将其扩展为与目标相同大小si…

【超详细】Fastjson 1.2.24 命令执行漏洞复现-JNDI简单实现反弹shell(CVE-2017-18349)

前言&#xff1a; 看了很多别人关于漏洞复现过程&#xff0c;很多博客过程简洁&#xff0c;有的过程过于复杂&#xff0c;比如看到写java代码&#xff0c;用javac进行编译等等。所以我想写出比较详细的漏洞复现过程。 一&#xff0c;漏洞介绍 1-1 fastjson是什么 fastjson是…

xorm数据库操作之Join、Union

golang的数据库操作xorm使用起来非常方便&#xff0c;不用再自己写SQl语句&#xff0c;而且xorm自己给我们做了SQL防注入等操作&#xff0c;用起来既方便又安全。此次文章我不会记录xorm的基本操作&#xff0c;我值记录一些特殊用法问题&#xff0c;包括动态创建表单、基于xorm…

Spring大白话--三级缓存解决循环依赖问题

文章目录 前言一、Spring 循环依赖是什么&#xff1f;二、Spring 三级缓存解决单例的循环依赖&#xff1a;2.1 Bean 单例对象生成的过程&#xff1a;2.2 三级缓存工作过程&#xff1a; 三、Spring 三级缓存无法解决的单例循环依赖情况&#xff1a;3.1 通过构造方法注入的bean &…

如何优化网站排名(百度SEO指南与优化布局方法)

百度SEO指南介绍&#xff1a;蘑菇号-www.mooogu.cn 首先&#xff0c;为了提高网站的搜索引擎优化排名&#xff0c;需要遵循百度SEO指南的规则和标准。这包括使用符合规范的网站结构、页面内容的质量和与目标用户相关的关键词。避免使用非法技术和黑帽SEO的方法。 增加百度SEO…

如何快速重置模型原点

1、什么是模型原点&#xff1f; 模型原点是三维建模中的概念&#xff0c;它是指在一个虚拟三维空间中确定的参考点。模型原点通常位于模型的几何中心或基本组件的中心位置。如图所示&#xff1a; 可以看到模型的原点在模型的几何中心 2、模型原点的作用 知道了什么是模型原点&…

AVL Cruise 2020.1 安装教程

文章目录 安装包安装破解 安装包 链接&#xff1a;https://pan.baidu.com/s/1GxbeDj_SyvKFyPeTsstvTQ?pwd6666 提取码&#xff1a;6666 安装 安装文件&#xff1a; 双击setup.exe&#xff1a; 一直netx&#xff0c;中间要修改两次路径&#xff0c;第一次是安装位置&#xf…

常用螺栓标准、规格、用途汇总表

螺栓 1 常用螺栓标准、用途 常用螺栓标准、规格、用途见表1。 表1 常用螺栓标准、规格、用途汇总表 注&#xff1a;1.冷镦工艺生产的小六角头螺栓具有材料利用率高、生产效率高、机械性能高等优点,但由于头部尺寸较小, 不宜用于多次装拆、被联接件强度较低和易锈蚀等场合。 2.…

Mac多协议传输和文件管理工具ForkLift 4

ForkLift 4 for Mac 是一个强大的文件管理工具&#xff0c;具有直观的界面和强大的功能。它提供了一个直观的界面&#xff0c;使用户能够轻松地管理他们的文件和目录&#xff0c;以及进行各种操作&#xff0c;如复制、移动、重命名、删除等。 它还支持多种文件传输协议&#x…