QT实现聊天室
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<mydialog.h>
#include<QMessageBox>
#include<QDebug>
#include<QTcpSocket>
#include<QTextStream>
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 <QMessageBox>
#include<QDebug>
#include<QTcpSocket>
#include<QTextStream>
#include<QDir>
#include<QFileDialog>
#include<QFileInfo>
#include<QFile>
#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<QString> list;//声明list容器对象成员变量
QList<QString>::iterator iter;//声明迭代器指针
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 <QThread>
#include<QFile>
#include<QTextStream>
#include<QByteArray>
#include<QTcpSocket>
#include<QDebug>
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()<<text;
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<<text;
}
//登录
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<<text;
}
//切换回主界面
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()<<name;
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<<text;
}
//本进程连接服务器
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<<text;
}
//创建下载目录
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<<text;
}
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()<<cmd;
QString text=cmd.append("\n").append(filename).append("\n").append("ip");
//创建文本流对象
QTextStream output(client);
//发送
output<<text;
//qDebug()<<text;
//屏蔽上传按钮
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()<<buffer;
// // 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()<<text;
//如果存在"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<<text;
}
//查询历史记录
void MyDialog::btnHisQClickedSlot()
{
ui->textBrowser->clear();
cmd="hisq";
QString text=cmd.append("\n").append("a").append("\n").append("b");
//创建文本流对象
QTextStream output(client);
output<<text;
}
//私发
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<<text;
}
//私聊的历史记录查询
void MyDialog::btnHisSClickedSlot()
{
ui->textBrowser->clear();
cmd="hiss";
QString text=cmd.append("\n").append(name).append("\n").append("b");
//创建文本流对象
QTextStream output(client);
output<<text;
}
//退出登录
void MyDialog::btnNoLogClickedSlot()
{
cmd="nologin";
QString text=cmd.append("\n").append(name).append("\n").append("b");
//创建文本流对象
QTextStream output(client);
output<<text;
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<<text;
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<<text;
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()<<buffer;
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 <QMessageBox>
#include<QTcpServer>
#include<QTcpSocket>
#include<QTextStream>
#include<QList>
#include<QDebug>
#include<QSqlDatabase>
#include<QSqlError>
#include<QSqlQuery>
#include<QDateTime>
#include<QDir>
#include"resivethread.h"
#include<QByteArray>
#include<QThread>
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*> clients;//连接类容器对象
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 <QThread>
#include<QTcpServer>
#include<QTcpSocket>
#include<QFile>
#include<QTextStream>
#include<QByteArray>
#include<QDebug>
#include<QDialog>
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
更多推荐



所有评论(0)