QT实现聊天室
qt实现聊天室 项目功能简介 1) 连接 客户端,需要先连接服务器。就是输入服务器端的IP和端口连接服务器,如果连接成功,连接按钮显示文字
qt实现聊天室
项目功能简介
1) 连接
客户端,需要先连接服务器。就是输入服务器端的IP和端口连接服务器,如果连接成功,连接按钮显示文字会显示已连接,颜色变浅。
2) 注册
接下来是注册,如果申请的用户名还有人用户注册,则可以注册成功,如果之前有用户注册过之后会显示注册失败。
3)登录
在接下来是登录,如果要登录的用户名还没有注册过,会显示未注册。如果密码错误会显示密码错误。如果换设备登录会显示新设备登录。如果用户名与密码都正确,则可以成功登录。
4)聊天
登录成功后就可以进入主界面。在主界面中,有三个功能区:用户管理、聊天、文本传输。
1)
用户管理功能区,可以更换昵称、更改头像、退出登录与注销账号
2)
聊天,可以群聊、私聊、群历史、私聊历史、删除私聊历史、显示好友列表、清屏
3)
文本传输,可以获取所有聊天室的用户,上传到服务器端的文件列表。还可以上传、下载文件。
1、项目运行展示
登录界面
聊天界面
1.1连接
1.2注册
1.3登录
1.4用户管理
1.5聊天
1)群聊
2)私聊
3)关闭历史记录显示(清屏)
4)群聊历史查询
5)私聊历史
6)清空私聊历史记录
7)我的好友
1.6文件传输
1)获取文件列表
2)上传文件
2、项目设计流程
服务器端一开始运行就会建立一个数据库文件。里面有四张表(注册表、登录表、群历史聊天记录表、私聊历史记录表)。
2.1 连接
客户端获取用户输入的IP和密码,建立一个连接对象,连接这个IP和端口的服务器。服务器端先是创建一个连接管理类对象,监听客户端连接。如果有客户端连接,创建一个唯一与之对应的连接对象。把他添加到容器中。
2.2 注册
客户端
获取用户输入的用户名与密码,拼接好后,创建一个文本流对象,发送给服务器。
服务器端
接受到客户端发来的消息,先判断是什么类型的消息,如果是注册消息,则调用对应的注册函数。在注册函数中会先调用查询注册表的函数,判断用户注册的用户名是否可以成功注册,如果可以,调用插入注册表的函数,将该用户注册的用户名与密码保存在注册表中,给客户端发送注册成功标志,如果错误,则发送注册失败标志。
客户端
接收服务器端发送过来的信息,判断是那一种标志,
如果是注册失败标志,则弹出“注册失败”对话框
如果是注册成功标志,则弹出“注册成功”对话框
2.3 登录
客户端
获取用户输入的用户名与密码,拼接好后,创建一个文本流对象,发送给服务器。
服务器端
接受到客户端发来的消息,先判断是什么类型的消息,如果是登录消息,则调用对应的登录函数。在登录函数中会先调用查询注册表的函数,判断用户登录的用户名是否已经注册。
1)如果没有注册过,则给客户端发送未注册标志。
2)如果该用户已经注册,但是密码不匹配,则给客户端发送密码错误标志
3)如果用户名与密码都正确,则给客户端发送登录成功标志。并去调用查登录表的函数,如果该用户第一次登录,需要把该用户的用户名、登录IP和端口插入到登录表中。如果已经登录过,则检测IP是否更换,未更换的话,给客户端发送成功登录的标志。如果更换则给它发送换设备标志,并更新登录表。
客户端
接收服务器端发送过来的信息,判断是那一种标志,
如果是未注册标志,则弹出“未注册”对话框
如果是是密码错误标志,则弹出“密码错误”对话框
如果是是登录成功标志,则弹出“登录成功”对话框,并跳转到主界面,关闭登录界面
如果是换设备标志,则弹出“换新设备登录”对话框,跳转到主界面,关闭登录界面
2.4 聊天
(1)群聊
客户端
获取用户输入消息内容,前面拼接上消息的类型,创建一个文本流对象,发送给服务器。
服务器端
接受到客户端发来的消息,先判断是什么类型的消息,如果是群聊消息,则调用对应的群聊函数。
将信息发送给其他客户端,并将信息加上用户名与时间存放到群聊历史记录表中。
客户端
接收服务器端发送过来的信息,将信息显示在聊天窗口
(2)群聊历史
客户端
将查询群聊历史的命令,创建一个文本流对象,发送给服务器。
服务器端
接受到客户端发来的消息,先判断是什么类型的消息,如果是查询群聊历史消息,则调用对应的查询群聊历史函数。在该函数中查询聊天记录,发送给客户端。
客户端
接收服务器端发送过来的信息,将信息显示在聊天窗口
(3)私聊
客户端
获取用户输入消息内容与接受此消息的用户,前面拼接上消息的类型,创建一个文本流对象,发送给服务器。
服务器端
接受到客户端发来的消息,先判断是什么类型的消息,如果是私聊消息,则调用对应的私聊函数。去查询注册表,如果有此用户,再去查询登录表,找到对应的IP和端口。通过迭代器指针遍历当前连接客户端对象容器,对比IP和端口,找到相同的客户端,将信息发送过去。并将信息加上用户名与时间存放到私聊历史记录表中。
客户端
接收服务器端发送过来的信息,将信息显示在聊天窗口
(4)查私聊历史
客户端
将查询私聊历史的命令,后面拼接上本用户的用户名,创建一个文本流对象,发送给服务器。
服务器端
接受到客户端发来的消息,先判断是什么类型的消息,如果是查询私聊消息,则调用对应的私聊函数。去查询私聊历史记录表,找到发给该用户的所有私聊信息,并将信息发送过去。
客户端
接收服务器端发送过来的信息,将信息显示在聊天窗口
(5)清空私聊历史
客户端
将查询私聊历史的命令,后面拼接上本用户的用户名,创建一个文本流对象,发送给服务器。
服务器端
接受到客户端发来的消息,先判断是什么类型的消息,如果是清空私聊历史消息,则调用对应的私聊函数。去删除指定用户的私聊历史记录表。
(6)查好友历史
客户端
将查询好友的命令,创建一个文本流对象,发送给服务器。
服务器端
接受到客户端发来的消息,先判断是什么类型的消息,如果是查询好友消息,则调用对应的查询好友函数。去查询注册表,将已注册的所有用户的用户名发送给客户端。
客户端
接收服务器端发送过来的信息,将信息显示在聊天窗口。
(7)关闭历史记录显示
则调用该组件的清空函数,清空显示。
2.5 文本传输
(1)获取文件列表
客户端
将查询文件的命令,后面拼接上,服务器给该聊天室创建的文件夹路径,创建一个文本流对象,发送给服务器。
服务器端
接受到客户端发来的消息,先判断是什么类型的消息,如果是查询文件列表消息,则调用对应的查询文件列表函数。去查指定路径下的文件夹信息,发送给客户端。
客户端
接收服务器端发送过来的信息,将信息显示在聊天窗口。
(2)上传文件
客户端
弹出打开文件的弹窗,在里面选择要发送的文件。
将上传的命令,后面拼接上该文件名,创建一个文本流对象,发送给服务器。接着创建一个线程对象,定义好进度条更新的信号与槽函数连接协议,调用start()函数,执行线程中run函数,发送文件内容给服务器。
服务器端
接受到客户端发来的消息,先判断是什么类型的消息,如果是上传文件消息,则调用对应的接受上传文件的函数。先接收客户端发送过来的文件名,创建一个线程对象,并通过构找函数传参的方式将文件名传给子线程,调用start()函数。执行子线程的run()函数。在run()函数中,先判断路径下有没有该文件,没有则创建。并将接受到的文件内容填充进去
3、完整代码
3.1客户端
1).pro文件
加上network网络通信模块
#-------------------------------------------------
#
# Project created by QtCreator 2023-07-20T14:39:05
#
#-------------------------------------------------
QT += core gui network
greaterThan(QT_MAJOR_VERSION, 4): QT += widgets
TARGET = UdpChatClient
TEMPLATE = app
SOURCES += main.cpp\
dialog.cpp \
mydialog.cpp \
sendthread.cpp
HEADERS += dialog.h \
mydialog.h \
sendthread.h
FORMS += dialog.ui \
mydialog.ui
RESOURCES += \
res.qrc
OTHER_FILES += \
iconfig.rc
RC_FILE += iconfig.rc
2)dialog.h文件
#ifndef DIALOG_H
#define DIALOG_H
#include
#include
#include
#include
#include
namespace Ui {
class Dialog;
}
class Dialog : public QDialog
{
Q_OBJECT
public:
explicit Dialog(QWidget *parent = 0);
~Dialog();
private:
Ui::Dialog *ui;
QTcpSocket *client;// 连接对象
MyDialog *md; //聊天窗口对象
private slots:
void btnConnectClickedSlot(); //连接的槽函数
void btnRegisterClickedSlot(); //注册的槽函数
void btnLogonClickedSlot(); //登录的槽函数
void conntedSlot(); //连接成功槽函数
void disconntedSlot();//断开连接槽函数
void readyreadSlot();//接受服务器端发送过来的标志
void switchInterfaceSlot(); //切换回主界面
};
#endif // DIALOG_H
3)mydialog.h文件
#ifndef MYDIALOG_H
#define MYDIALOG_H
#include
#include
#include
#include
#include
#include
#include
#include
#include"sendthread.h"
namespace Ui {
class MyDialog;
}
class MyDialog : public QDialog
{
Q_OBJECT
public:
explicit MyDialog(QString name,QString ip,int port,QWidget *parent = 0);
~MyDialog();
private:
Ui::MyDialog *ui;
QString name; //用户名
QTcpSocket *client; //连接对象
QString cmd; //命令
QString readPath; //读路径
QList
QList
QString ip; //获取服务器的ip和端口
int port;
void connntPort(); //建立本进程与服务器端的连接
void updataPort(); //更新端口
void creatFolder(); //创建下载目录
private slots:
void btnSendClickedSlot();//群发
void btnHisQClickedSlot();//群历史聊天记录查询
void btnSendUsrClickedSlot();//私发
void btnHisSClickedSlot();//私聊自己的历史记录
void btnSelectChatUsrClickedSlot();//查询聊天室的成员
void btnNoLogClickedSlot();//退出登录
void btnNoResClickedSlot();//注销账户
void btnClearClickedSlot();//清空历史记录
void btnCloseDpClieckedSlot();//关闭历史记录显示
void btnGetFileListSlot(); //获取文件列表
void btnSendFileSlot(); //上传文件
void btnDownloadSlot(); //下载文件
void mydialogReadyreadSlot();//接受消息
void btnSetnameClickedSlot();//修改昵称
void btnSelectPtoClickedSlot();//选择头像
void btnSurePhoClickedSlot(); //确认头像
// void sendValueSlot(int); //更新上传文件进度条
void sendValueSlot(int);
void sendFinishSlot();
signals:
void switchInterface();//切换回主界面信号
};
#endif // MYDIALOG_H
4)sendthread.h文件(上传文件子线程)
#ifndef SENDTHREAD_H
#define SENDTHREAD_H
#include
#include
#include
#include
#include
#include
class SendThread : public QThread
{
Q_OBJECT
public:
explicit SendThread(QTcpSocket *client,QString readpth,QObject *parent = 0);
protected:
void run();
private:
QString readpth;
QString ip; //服务器端ip
int port;
QTcpSocket *client;
void threadClickedSlot();
signals:
void sendValueSignal(int);
void sendFinish();
public slots:
};
#endif // SENDTHREAD_H
5)dialog.cpp文件
#include "dialog.h"
#include "ui_dialog.h"
Dialog::Dialog(QWidget *parent) :
QDialog(parent),
ui(new Ui::Dialog)
{
ui->setupUi(this);
//连接、登录、注册按钮点击时触发的信号
connect(ui->pushButtonConn,SIGNAL(clicked()),this,SLOT(btnConnectClickedSlot()));
connect(ui->pushButtonRegister,SIGNAL(clicked()),this,SLOT(btnRegisterClickedSlot()));
connect(ui->pushButtonLogon,SIGNAL(clicked()),this,SLOT(btnLogonClickedSlot()));
//创建一个TCP连接类对象
client =new QTcpSocket(this);
//连接状态改变时触发的信号
connect(client,SIGNAL(connected()),this,SLOT(conntedSlot()));
connect(client,SIGNAL(disconnected()),this,SLOT(disconntedSlot()));
//接受到服务器发送过来的数据触发
connect(client,SIGNAL(readyRead()),this,SLOT(readyreadSlot()));
}
Dialog::~Dialog()
{
disconnect(client,SIGNAL(disconnected()),this,SLOT(disconntedSlot()));
if(client->isOpen())
client->close();
delete ui;
}
//连接槽函数
void Dialog::btnConnectClickedSlot()
{
//获取用户输入的ip和端口
QString ip=ui->lineEditIP->text();
int port=ui->spinBox->value();
////为了解决第一次输入错误的IP和端口不能连接的问题
//终止当前连接
client->abort();
//建立新的连接对象
client =new QTcpSocket(this);
////新的连接对象也需要建立这些信号的约定
//连接状态改变时触发的信号
connect(client,SIGNAL(connected()),this,SLOT(conntedSlot()));
connect(client,SIGNAL(disconnected()),this,SLOT(disconntedSlot()));
//接受到服务器发送过来的数据触发
connect(client,SIGNAL(readyRead()),this,SLOT(readyreadSlot()));
//连接服务器
client->connectToHost(ip,port);
//设置标题
setWindowTitle("聊吧");
}
//成功连接
void Dialog::conntedSlot()
{
//屏蔽连接按钮
ui->pushButtonConn->setEnabled(false);
//回复登录、注册按钮
ui->pushButtonRegister->setEnabled(true);
ui->pushButtonLogon->setEnabled(true);
ui->pushButtonConn->setText("已连接");
}
//连接断开
void Dialog::disconntedSlot()
{
//恢复连接按钮
ui->pushButtonConn->setEnabled(true);
//屏蔽登录、注册按钮
ui->pushButtonRegister->setEnabled(false);
ui->pushButtonLogon->setEnabled(false);
ui->pushButtonConn->setText("连接");
QMessageBox::warning(this,"提示","连接已断开");
}
//接受服务器端发送过来的标志,执行相应的逻辑处理
void Dialog::readyreadSlot()
{
//获取用户输入的ip和端口
QString ip=ui->lineEditIP->text();
int port=ui->spinBox->value();
QTextStream input(client);
QString text=input.readLine(256);
//qDebug()< if(text=="register sucess") QMessageBox::information(this,"提示","注册成功"); else if(text=="register fause") QMessageBox::warning(this,"提示","注册失败,用户名已存在"); else if(text=="nouser") QMessageBox::warning(this,"提示","登录失败,该用户名还没有注册,请先注册"); else if(text=="pwderr") QMessageBox::warning(this,"提示","登录失败,密码错误,请重新输入"); else if(text=="loginsuccess") { QString name=ui->lineEditUsr->text(); md=new MyDialog(name,ip,port); connect(md,SIGNAL(switchInterface()),this,SLOT(switchInterfaceSlot()));//切换回主界面的连接信号槽的约定 md->show(); this->close(); } else if(text=="deviceh") { QMessageBox::warning(this,"提示","登录成功,该账号使用新设备登录"); QString name=ui->lineEditUsr->text(); md=new MyDialog(name,ip,port); connect(md,SIGNAL(switchInterface()),this,SLOT(switchInterfaceSlot()));//切换回主界面的连接信号槽的约定 md->show(); this->close(); } } //注册 void Dialog::btnRegisterClickedSlot() { QString name=ui->lineEditUsr->text(); if(name=="") { QMessageBox::warning(this,"提示","请输入用户名"); return; } QString pwd=ui->lineEditPwd->text(); if(pwd=="") { QMessageBox::warning(this,"提示","请输入密码"); return; } QString cmd="register"; //拼接 QString text=cmd.append("\n").append(name).append("\n").append(pwd); //创建文本流类 QTextStream output(client); //发送消息 output< } //登录 void Dialog::btnLogonClickedSlot() { QString name=ui->lineEditUsr->text(); if(name=="") { QMessageBox::warning(this,"提示","请输入用户名"); return; } QString pwd=ui->lineEditPwd->text(); if(pwd=="") { QMessageBox::warning(this,"提示","请输入密码"); return; } QString cmd="login"; //拼接 QString text=cmd.append("\n").append(name).append("\n").append(pwd); //创建文本流类 QTextStream output(client); //发送消息 output< } //切换回主界面 void Dialog::switchInterfaceSlot() { Dialog *dz=new Dialog; dz->show(); md->close(); } 6)mydialog.cpp文件 #include "mydialog.h" #include "ui_mydialog.h" MyDialog::MyDialog(QString name,QString ip,int port,QWidget *parent) : QDialog(parent),name(name),ip(ip),port(port), ui(new Ui::MyDialog) { client = new QTcpSocket(this); ui->setupUi(this); qDebug()< creatFolder();//创建目录 //按钮触发的槽函数(群发送、群历史记录、私聊、私聊历史记录、退出登录、注销账户、清空私聊历史记录) connect(ui->pushButtonSend,SIGNAL(clicked()),this,SLOT(btnSendClickedSlot())); connect(ui->pushButtonHisQ,SIGNAL(clicked()),this,SLOT(btnHisQClickedSlot())); connect(ui->pushButtonSendUsr,SIGNAL(clicked()),this,SLOT(btnSendUsrClickedSlot())); connect(ui->pushButtonHisS,SIGNAL(clicked()),this,SLOT(btnHisSClickedSlot())); connect(ui->pushButtonNoLog,SIGNAL(clicked()),this,SLOT(btnNoLogClickedSlot())); connect(ui->pushButtonNoRes,SIGNAL(clicked()),this,SLOT(btnNoResClickedSlot())); connect(ui->pushButtonClear,SIGNAL(clicked()),this,SLOT(btnClearClickedSlot())); //关闭历史记录显示 connect(ui->pushButtonClosedp,SIGNAL(clicked()),this,SLOT(btnCloseDpClieckedSlot())); //按钮触发文件上传、下载 connect(ui->pushButtonGetFileList,SIGNAL(clicked()),this,SLOT(btnGetFileListSlot())); connect(ui->pushButtonSendFile,SIGNAL(clicked()),this,SLOT(btnSendFileSlot())); connect(ui->pushButtonDownload,SIGNAL(clicked()),this,SLOT(btnDownloadSlot())); //按钮触发修改头像、昵称 connect(ui->pushButtonSelectPho,SIGNAL(clicked()),this,SLOT(btnSelectPtoClickedSlot())); connect(ui->pushButtonSurePho,SIGNAL(clicked()),this,SLOT(btnSurePhoClickedSlot())); connect(ui->pushButtonSetname,SIGNAL(clicked()),this,SLOT(btnSetnameClickedSlot())); //获取好友列表 connect(ui->pushButtonSelectChatUsr,SIGNAL(clicked()),this,SLOT(btnSelectChatUsrClickedSlot())); //接受到消息时触发的槽函数 connect(client,SIGNAL(readyRead()),this,SLOT(mydialogReadyreadSlot())); //连接服务器(因为换页面进程了,端口号换了,需要重新连接) connntPort();//本进程连接服务器 updataPort();//更新登录表 //设置头像 list.append(":/new/prefix1/b.jpg"); list.append(":/new/prefix1/a.jpg"); list.append(":/new/prefix1/d.jpg"); list.append(":/new/prefix1/c.jpg"); list.append(":/new/prefix1/e.jpg"); list.append(":/new/prefix1/f.jpg"); //初始化迭代器指针 iter=list.begin(); //设置图片大小为适应Label QSize size(ui->labelPixmap->width(),ui->labelPixmap->height()); QPixmap pic(*iter); pic=pic.scaled(size,Qt::KeepAspectRatioByExpanding); ui->labelPixmap->setPixmap(*iter); //设置图标 QString icoPath=":/new/prefix1/sun.ico"; QIcon ico(icoPath); setWindowIcon(ico); } MyDialog::~MyDialog() { if(client->isOpen()) client->close(); delete ui; } //换昵称 void MyDialog::btnSetnameClickedSlot() { QString username=ui->lineEditSetname->text(); this->setWindowTitle(username); } //选择头像 void MyDialog::btnSelectPtoClickedSlot() { //如果向上翻到最后一张,就把迭代器指针指向第一张图片 if(*iter==":/new/prefix1/f.jpg") { qDebug()<<"6"; iter=list.begin(); } //向下,迭代器指针++ else { ++iter; } //设置图片大小为适应Label QSize size(ui->labelPixmap->width(),ui->labelPixmap->height()); QPixmap pic(*iter); pic=pic.scaled(size,Qt::KeepAspectRatioByExpanding); ui->labelPixmap->setPixmap(*iter); } //确认头像 void MyDialog::btnSurePhoClickedSlot() { QMessageBox::information(this,"提示","确认更换"); } void MyDialog::btnSelectChatUsrClickedSlot() { cmd="selectChatUsr"; QString text=cmd.append("\n").append(name).append("\n").append(ip); QTextStream output(client); output< } //本进程连接服务器 void MyDialog::connntPort() { client->connectToHost(ip,port); } //更新服务器端登录表 void MyDialog::updataPort() { cmd="updataPort"; QString text=cmd.append("\n").append(name).append("\n").append(ip); QTextStream output(client); output< } //创建下载目录 void MyDialog::creatFolder() { qDebug()<<"建目录"; QDir dir; QString path="D:/XinClientFileDownLoad"; if(dir.mkdir(path)) qDebug()<<"创建目录成功"; else { qDebug()<<"创建目录失败"; } } //获取文件列表 void MyDialog::btnGetFileListSlot() { //获取服务器端指定文件夹路径 QString path="D:/XinServerFileDownLoad"; cmd="getFileList"; QString text=cmd.append("\n").append(path).append("\n").append("a"); //创建文本流对象 QTextStream output(client); output< } void MyDialog::sendFinishSlot() { qDebug()<<"写入完成"; } //上传文件 void MyDialog::btnSendFileSlot() { cmd="sendFile"; QString fileter="所有文件(*.*);;文本文件(*.txt);;Qt(*.cpp *.h *.ui)"; QString path=QFileDialog::getOpenFileName(this, "打开", "D:/XinServerFileDownLoad", fileter); if(path==""&&readPath=="") { QMessageBox::warning(this,"提示","请选择文件!"); return; } if(path==""&&readPath!="") return; readPath=path; //获取文件名 QFileInfo info(readPath); QString filename=info.fileName(); // qDebug()< QString text=cmd.append("\n").append(filename).append("\n").append("ip"); //创建文本流对象 QTextStream output(client); //发送 output< //qDebug()< //屏蔽上传按钮 ui->pushButtonSendFile->setEnabled(false); // QThread::msleep(8000); SendThread *st=new SendThread(client,readPath,this); connect(st,SIGNAL(sendValueSignal(int)),this,SLOT(sendValueSlot(int))); connect(st,SIGNAL(sendFinish()),this,SLOT(sendFinishSlot())); st->start(); // //创建读对象 // QFile readFile(readPath); // readFile.open(QIODevice::ReadOnly); // //获取文件总大小 // qint64 totalSize=readFile.size(); // qint64 hasRead=0; // int lastper=0; // QByteArray buffer; // while(!readFile.atEnd()) // { // buffer=readFile.read(1024); // qDebug()< // // hasRead+=client->write(buffer); // client->waitForBytesWritten(true); // int per=hasRead*100/totalSize; // ui->progressBarSend->setValue(per); // } // ui->pushButtonSendFile->setEnabled(true); } void MyDialog::sendValueSlot(int value) { ui->progressBarSend->setValue(value); if(value==100) ui->pushButtonSendFile->setEnabled(true); } //下载文件 void MyDialog::btnDownloadSlot() { } //接受消息 void MyDialog::mydialogReadyreadSlot() { if(cmd=="hisq"||cmd=="hiss") ui->textBrowser->clear(); QTextStream input(client); QString text=input.readAll(); qDebug()< //如果存在"end"则移除 QString e="end"; text.remove(e); ui->textBrowser->append(text); } //发送消息 void MyDialog::btnSendClickedSlot() { cmd="chatq"; QString msg=ui->lineEdit->text(); if(msg=="") { QMessageBox::warning(this,"提示","请输入要发送的内容"); return; } QString text=cmd.append("\n").append(name).append("\n").append(msg); //创建文本流对象 QTextStream output(client); output< } //查询历史记录 void MyDialog::btnHisQClickedSlot() { ui->textBrowser->clear(); cmd="hisq"; QString text=cmd.append("\n").append("a").append("\n").append("b"); //创建文本流对象 QTextStream output(client); output< } //私发 void MyDialog::btnSendUsrClickedSlot() { qDebug()<<"私发"; cmd="chats"; QString msg=ui->lineEdit->text(); if(msg=="") { QMessageBox::warning(this,"提示","请输入要发送的内容"); return; } QString resiveuser=ui->lineEditSendUser->text(); if(resiveuser=="") { QMessageBox::warning(this,"提示","请输入指定接收者"); return; } QString text=cmd.append("\n").append(name).append("\n").append(resiveuser).append("\n").append(msg); //创建文本流对象 QTextStream output(client); output< } //私聊的历史记录查询 void MyDialog::btnHisSClickedSlot() { ui->textBrowser->clear(); cmd="hiss"; QString text=cmd.append("\n").append(name).append("\n").append("b"); //创建文本流对象 QTextStream output(client); output< } //退出登录 void MyDialog::btnNoLogClickedSlot() { cmd="nologin"; QString text=cmd.append("\n").append(name).append("\n").append("b"); //创建文本流对象 QTextStream output(client); output< emit switchInterface();//发送切换界面信号 } //注销账户 void MyDialog::btnNoResClickedSlot() { QMessageBox::StandardButton result=QMessageBox::question(this,"question","你是否要注销该账户"); if(result==QMessageBox::Yes) { cmd="noregister"; QString text=cmd.append("\n").append(name).append("\n").append("b"); //创建文本流对象 QTextStream output(client); output< emit switchInterface();//发送切换界面信号 } } //清空私聊历史记录 void MyDialog::btnClearClickedSlot() { QMessageBox::StandardButton result=QMessageBox::question(this,"question","你是否要清空聊天记录"); if(result==QMessageBox::Yes) { cmd="SClear"; QString text=cmd.append("\n").append(name).append("\n").append("b"); //创建文本流对象 QTextStream output(client); output< ui->textBrowser->clear(); } } //关闭历史记录显示 void MyDialog::btnCloseDpClieckedSlot() { ui->textBrowser->clear(); } 7)sendthread.cpp文件 #include "sendthread.h" SendThread::SendThread(QTcpSocket *client,QString readpth,QObject *parent) : QThread(parent) { this->client=client; this->readpth=readpth; } void SendThread::run() { qDebug()<<"子线程run函数"; QFile readFile(readpth); readFile.open(QIODevice::ReadOnly); qint64 totalSize=readFile.size(); qint64 hasRead=0; int lastper=0; QByteArray buffer; while(!readFile.atEnd()) { buffer=readFile.read(1024); //qDebug()< hasRead+=client->write(buffer); int per=hasRead*100/totalSize; if(per!=lastper) { emit sendValueSignal(per); lastper=per; } } //收尾 readFile.flush();//清空读缓存区 readFile.close();//关闭 } 8)ui文件 登录界面设计 主界面 3.2服务器端 1).pro文件 一定要加上sql(数据库模块)和network(网络模块) #------------------------------------------------- # # Project created by QtCreator 2023-07-22T09:02:38 # #------------------------------------------------- QT += core gui network sql greaterThan(QT_MAJOR_VERSION, 4): QT += widgets TARGET = UdpChatMyServer TEMPLATE = app SOURCES += main.cpp\ dialog.cpp \ resivethread.cpp HEADERS += dialog.h \ resivethread.h FORMS += dialog.ui QMAKE_CXXFLAGS += -std=c++11 RESOURCES += \ res.qrc OTHER_FILES += \ icoConfig.rc RC_FILE += icoConfig.rc 2)dialog.h #ifndef DIALOG_H #define DIALOG_H #include #include #include #include #include #include #include #include #include #include #include #include"resivethread.h" #include #include namespace Ui { class Dialog; } class Dialog : public QDialog { Q_OBJECT public: explicit Dialog(QWidget *parent = 0); ~Dialog(); private: Ui::Dialog *ui; QTcpServer *server;//服务器管理类对象 QList QTcpSocket *socket;//一个新连接对象 QSqlDatabase db; //数据库对象 void connect2DB(); //连接数据库 void createTable(); //建表 void insertResgisterData(QString,QString); //插入注册表 void insertLongonData(QString,QString,quint16); //插入登录表 void insertHisQData(QString,QString,QString); //插入群历史聊天记录表 void insertHisSData(QString name,QString resiveuser,QString msg,QString time);//插入私聊记录表 void deleteRegisterUser(QString name);//删除注册信息 void deleteHistorySChat(QString name);//删除私聊历史记录 void creatFolder(); //创建目录 void sendFolderContent(QString folderpath);//发送文件列表给客户端 void resiveFile(QString writeFilename,QString ip); void selectChatUsr(); //查在已注册的用户 private slots: void newConnSlot();//新链接来了 void disconntedSlot();//链接断开 void readyreadSlot();//接受数据 void readyreadResgisterSlot(QString,QString);//注册 void readyreadLogonSlot(QString,QString);//登录 int isDataRNamePwdExists(QString,QString);//查注册表 int isDataLNameIpPortExists(QString,QString,quint16);//查登录表 void updateData(QString name,QString ip,quint16 port);//更新登录表 void readreadChatQSlot(QString,QString);//聊天(群里) void readreadHisQSlot(); //查询历史记录表 int isDataLNameIpPortExistsS(QString name,QString& ip,quint16& port);//私聊专用查登录表(需要用到参数返回接受者的ip和端口) void readreadChatSSlot(QString,QString,QString); //私聊 void readreadHisSSlot(QString name); //查询私聊历史记录表 // void resiveFile(QString writeFilename,QString ip); void fileWriteFinishSlot(); }; #endif // DIALOG_H 3)resivethread.h #ifndef RESIVETHREAD_H #define RESIVETHREAD_H #include #include #include #include #include #include #include #include class ResiveThread : public QThread { Q_OBJECT public: explicit ResiveThread(QTcpSocket *client,QString,QObject *parent = 0); protected: void run(); private: QTcpSocket *client; int port; QString resivename; //接受文件路径 signals: void fileWriteFinish(); public slots: }; #endif // RESIVETHREAD_H