目录
项目要求
项目背景
技术分析
架构设计
服务器架构
模块划分
模块之间的交互
客户端架构
模块划分
模块之间交互
项目展示
项目实现
服务器
ui
server.pro
dialog.h
dialog.cpp
客户端
ui
cient.pro
dialog.h
dialog.cpp
打包步骤不做演示
视频演示
项目要求
【必做内容】
1. 多人在线聊天室公聊
2. 聊天记录保存与搜索
3. 界面设计与美化
4. 打包
【选做内容】
1. 私聊
2. 群文件上传与下载
3. 账户管理
4. 登录人脸检测
......
项目背景
在当今互联网时代,即时通讯已经成为人们日常生活中不可或缺的一部分。为了掌握网络编程和跨平台GUI开发的技能,我决定使用Qt框架完成一个多人聊天工作室项目。该项目旨在实现一个简单而实用的多人聊天应用,允许多个用户在同一时间进行文字交流等。
为了实现这一目标,我选择了Qt框架作为开发工具。Qt提供了丰富的网络编程库和易用的GUI开发工具,同时具有跨平台特性,这使得它成为我的首选。在开始项目之前,我对Qt框架的相关知识进行了深入学习,并熟悉了其网络模块、信号与槽机制以及界面设计工具。
总的来说,多人聊天室是一种常见的网络应用,它允许多个用户之间进行实时的文字交流,并且我也额外附加了一些功能,在这个项目中,我使用了Qt框架,结合了其强大的网络通信和图形界面开发功能,实现了一个简单、美观、实用的多人聊天工作室应用。
技术分析
注册 登录:在实现注册和登录功能时,我利用了Qt框架的网络编程库和数据存储技术。用户注册时,我采用了用户名和密码的方式进行账户信息的创建并将其发到服务器,将用户信息存储在服务器的数据库中。相同账户注册时,会从服务器进行查询,如果查到账号已存在则不能完成二次注册,而在登录时,我通过验证用户输入的用户名和密码与数据库中存储的信息是否匹配来实现用户的身份认证。
ip及端口选择:使用复选框以及相关信号槽机制等,完成用户可自主设置选择ip和端口,增强了系统的完整性和灵活性。
群发信息:每当一个客户端链接时,服务器会将其保存到表中,客户端发送信息给服务器,服务器遍历转发。从而实现一对多的信息交互。
历史记录查找:服务端将收到的消息存储到服务器端的数据库中,以便后续查找使用。用户可以调用相关函数接口完成对消息记录的查询。
架构设计
服务器架构
模块划分
网络模块: 负责监听客户端的连接请求,接受客户端的消息,并将消息转发给其他客户端。
用户管理模块: 负责管理用户的登录、退出,以及在线用户列表的维护。
消息处理模块: 负责对接收到的消息进行解析和处理,比如区分做什么指令等的处理逻辑。
持久化模块: 负责将用户信息、聊天记录等数据持久化到数据库中,以便实现用户信息的持久存储。
模块之间的交互
网络模块与消息处理模块: 网络模块接收到消息后,将消息传递给消息处理模块进行解析和处理,然后再根据消息类型进行相应的转发操作。
用户管理模块与持久化模块: 当用户登录或登出时,用户管理模块需要与持久化模块进行交互,将用户信息同步到数据库中。
客户端架构
模块划分
用户界面模块: 负责展示用户界面,包括登录注册页面、聊天页面、查询记录界面等。
网络通信模块: 负责与服务器端进行通信,发送消息、接收消息等操作。
用户行为响应模块: 监听用户在界面上的操作,比如发送消息、点击选择发送对象、文件传输等,然后触发相应的响应动作。
模块之间交互
用户界面模块与网络通信模块: 用户界面模块需要通过网络通信模块来发送用户输入的消息,并接收服务器端返回的消息。
用户界面模块与用户行为响应模块: 用户界面上的各种操作会触发用户行为响应模块中的相应函数,从而实现用户行为与系统操作的响应。
项目展示
项目实现
服务器
ui
server.pro
#-------------------------------------------------
#
# Project created by QtCreator 2024-10-22T16:49:57
#
#-------------------------------------------------QT += core gui network sql
RC_FILE += icon_config.rc
greaterThan(QT_MAJOR_VERSION, 4): QT += widgetsTARGET = server
TEMPLATE = appSOURCES += main.cpp\dialog.cppHEADERS += dialog.hFORMS += dialog.uiRESOURCES += \res.qrcDISTFILES += \icon_config.rc
dialog.h
#ifndef DIALOG_H
#define DIALOG_H#include <QDialog>
#include <QTcpServer> // 服务器管理类
#include <QDebug>
#include <QDateTime>
#include <QTcpSocket> // 网络连接类
#include <QTextStream> // 文本流#include <QButtonGroup>
#include <QMessageBox>
#include <QSqlDatabase> // 数据库连接类
#include <QSqlError> // 错误信息类
#include <QSqlQuery> // 数据库操作类
#include<QPixmap>
#include<QPainter>//画家对象namespace Ui {
class Dialog;
}class Dialog : public QDialog
{Q_OBJECTpublic:explicit Dialog(QWidget *parent = 0);~Dialog();protected://创建画家对像 注意就是这个名字 发生倾斜就是对了void paintEvent(QPaintEvent *);private:Ui::Dialog *ui;QTcpServer* server;QTcpSocket* socket = NULL; // 下的蛋QList<QTcpSocket*>clients;void printMsg(QString); // 在公屏显示信息void connect2DB();QSqlDatabase db; // 数据库连接对象void createChatTable(); // 建聊天记录表void createLoginTable();//建登录信息表void selectTime(QString,int i);void selectNickname(QString);void selectMsg(QString);void selectAll();bool isDataExists(QString id); // 判断某个id的数据在不在bool isLoginExists(QString id,QString password); //判断账号密码信息private slots:void newConnectionSlot(); // 建立新连接的槽函数!void readyReadSlot(); // 准备读的槽函数void disconnSlot(); //连接断开的槽函数};#endif // DIALOG_H
dialog.cpp
#include "dialog.h"
#include "ui_dialog.h"
#include <QThread>Dialog::Dialog(QWidget *parent) :QDialog(parent),ui(new Ui::Dialog)
{ui->setupUi(this);// 界面置顶setWindowFlags(Qt::WindowStaysOnTopHint);server = new QTcpServer(this);// 开启监听bool result = server->listen(QHostAddress::Any,7456);if(result){printMsg("监听开启成功,端口号7456");connect(server,SIGNAL(newConnection()),this,SLOT(newConnectionSlot()));}elseprintMsg("监听开启失败!");//连接数据库connect2DB();
}Dialog::~Dialog()
{// 关闭server->close();// 如果数据库连接还在打开,则关闭if(db.isOpen())db.close();delete ui;
}void Dialog::paintEvent(QPaintEvent *)
{///创建画家对象/// 参数为哪儿画,继承QPaintDevice的类对象才能被绘制QPainter painter(this);//创建一个要画的图片对象QPixmap pic(":/new/prefix1/bd.jpg");//开始绘制//参数1/2:绘制的坐标;//参数3&4:绘制的宽高;//参数5:绘制的内容;painter.drawPixmap(0,0,this->width(),this->height(),pic);//使lineEdit控件透明ui->textBrowser->setStyleSheet("QTextBrowser { background-color: transparent; }");ui->lineEditCount->setStyleSheet("QLineEdit { background-color: transparent; }");
}
/*** @brief Dialog::printMsg 在公屏上显示信息* @param msg 要显示的信息*/
void Dialog::printMsg(QString msg)
{// 获得日期时间QString dt = QDateTime::currentDateTime().toString("yyyy-MM-dd hh:mm:ss");// 显示到公屏上ui->textBrowser->append(dt);ui->textBrowser->append(msg);
}//创建并连接数据库
void Dialog::connect2DB()
{// 创建连接对象db = QSqlDatabase::addDatabase("QSQLITE");// 设置数据库文件名称db.setDatabaseName("chat_msg.db");// 打开数据库连接if(db.open()){qDebug() << "连接成功!";// 建表createLoginTable();createChatTable();}else{// 获得错误细信息封装类QSqlError info = db.lastError();// 提取错误信息QString text = info.text();// 展示错误QMessageBox::critical(this,"错误",text);}
}//创建注册登录表
void Dialog::createLoginTable()
{QString sql = "CREATE TABLE login_msg(user_name TEXT,password TEXT);";// 创建数据库操作类对象QSqlQuery sq;if(sq.exec(sql)) // 如果执行成功{qDebug() << "建表成功!";}else //失败{// 获得错误细信息封装类QSqlError info = sq.lastError();// 提取错误信息QString text = info.text();qDebug() << "建表失败!" << text;}
}//创建聊天表
void Dialog::createChatTable()
{QString sql = "CREATE TABLE chat(dt TEXT,nickname TEXT,msg TEXT);";// 创建数据库操作类对象QSqlQuery sq;if(sq.exec(sql)) // 如果执行成功{qDebug() << "建表成功!";}else //失败{// 获得错误细信息封装类QSqlError info = sq.lastError();// 提取错误信息QString text = info.text();qDebug() << "建表失败!" << text;}
}//新连接
void Dialog::newConnectionSlot()
{socket=server->nextPendingConnection();QTextStream output(socket);if(clients.size()>=20){qDebug()<<"客户端已满";output<<QString("客户端已满,连接失败!");socket->close();}printMsg("新连接已建立!");clients.append(socket);//显示连接数ui->lineEditCount->setText(QString::number(clients.size()));// 读取消息的信号槽connect(socket,SIGNAL(readyRead()),this,SLOT(readyReadSlot()));//掉线的信号槽connect(socket,SIGNAL(disconnected()),this,SLOT(disconnSlot()));// 拿到对面的IP地址和端口号并展示QString ip = socket->peerAddress().toString();quint16 port = socket->peerPort();QString text = ip.append(":") + QString::number(port);printMsg(text.append(" 已上线"));ui->textBrowser->append("");//给客户端打招呼output << QString("欢迎来到聊天室!");
}//读
void Dialog::readyReadSlot()
{socket=(QTcpSocket*)sender();for(int i=0;i<clients.size();i++){
// if(socket==clients.at(i))if(clients.at(i)->isReadable() && clients.at(i)->bytesAvailable()>0){//建立读通道QTextStream input(clients.at(i));QString text = input.readAll();//建立写通道QTextStream output(socket);//将读到的信息格式处理QStringList list = text.split(":");//注册信息,服务器接收通过“:”拆分长度为2if(list.size()==2){QString id=list.value(0);QString password=list.value(1);if(isDataExists(id)){//账号已存在,不能注册output << QString("账号已存在");qDebug()<<"账号已存在";}else{// 预处理的SQL语句QString sql = "INSERT INTO login_msg VALUES(?,?)";QSqlQuery sq;sq.prepare(sql); // 预处理// 绑定参数sq.addBindValue(id);sq.addBindValue(password);// 执行绑定后的SQL语句if(sq.exec()){output<<QString("注册成功");qDebug()<<"注册数据插入成功!";}else //失败{// 获得错误细信息封装类QSqlError info = sq.lastError();// 提取错误信息QString msg = info.text();msg.prepend("数据插入操作失败!");QMessageBox::warning(this,"通知",msg);}}}//服务器接收通过“:”拆分长度为3if(list.size()==3){if(list.value(0)=="按时间查询"){QString datatime=list.value(1);selectTime(datatime,i);}else if(list.value(0)=="按昵称查询"){QString nickname=list.value(1);selectNickname(nickname);}else if(list.value(0)=="按消息内容查询"){QString msg=list.value(1);selectMsg(msg);}else{//登录QString user_name = list.value(0);QString password = list.value(1);//账号密码正确,登陆成功if(isLoginExists(user_name,password)){output << QString("登录成功");}else{output<<QString("登录失败");}}}//收到聊天信息,服务器接收通过“:”拆分长度为4if(list.size()==4){// 获得用户输入数据QString dt= list.value(0);QString nickname = list.value(1);QString msg = list.value(2);// 预处理的SQL语句QString sql = "INSERT INTO chat VALUES(?,?,?)";QSqlQuery sq;sq.prepare(sql); // 预处理// 绑定参数sq.addBindValue(dt);sq.addBindValue(nickname);sq.addBindValue(msg);// 执行绑定后的SQL语句if(sq.exec()){qDebug()<<"聊天数据插入成功!";//发送到所有用户聊天界面for(int m=0;m<clients.size();m++){if(m==i)continue;socket=clients.at(m);QTextStream output2(clients.at(m));output2<<dt<<":"<<nickname<<":"<<msg;//客户端接收通过“:”拆分长度为3}}else //失败{// 获得错误细信息封装类QSqlError info = sq.lastError();// 提取错误信息QString msg = info.text();msg.prepend("聊天数据插入操作失败!");QMessageBox::warning(this,"通知",msg);}}//客户端接收通过“:”拆分长度为1if(list.size()==1){//查询所有聊天记录selectAll();}}}
}//判断id存不存在
bool Dialog::isDataExists(QString id)
{// QString idText = QString::number(id);QString sql = "SELECT * FROM login_msg WHERE user_name=";sql.append(id); // 拼接,只为证明也可以,但不建议QSqlQuery sq;if (sq.exec(sql)){bool found = false; //通过设定状态验证时候查询到数据while (sq.next()) //查询不到消息,sq.next()为零{if (!found){found = true;}return true;}if (!found){return false;}}
}//查询账号密码
bool Dialog::isLoginExists(QString user_name, QString password)
{QString sql = "SELECT * FROM login_msg WHERE user_name=? AND password=?";QSqlQuery sq;sq.prepare(sql);sq.addBindValue(user_name);sq.addBindValue(password);if(sq.exec()) // 查询成功{return sq.next(); // 直接返回有无数据}else{return false;}
}//按时间查询
void Dialog::selectTime(QString dt,int i)
{QTextStream output(clients.at(i));QString sql = "SELECT * FROM chat WHERE dt LIKE?";QSqlQuery sq;sq.prepare(sql);sq.addBindValue(dt);if (sq.exec()){bool found = false; //通过设定状态验证时候查询到数据while (sq.next()) //查询不到消息,sq.next()为零{if (!found){found = true;}QString time = sq.value(0).toString();QString nickname = sq.value(1).toString();QString msg = sq.value(2).toString();output << time << ":" << nickname << ":" << msg << ":" << "end";}if (!found){qDebug() << "未查询到符合条件的记录。";output<<QString("查询失败"); //客户端接收通过“:”拆分长度为1}}else{// 获得错误细信息封装类QSqlError info = sq.lastError();// 提取错误信息QString msg = info.text();msg.prepend("查询操作失败!");QMessageBox::warning(this,"通知",msg);}
}//按昵称查询
void Dialog::selectNickname(QString nickname)
{QTextStream output(socket);// 预处理的SQLQString sql = "SELECT * FROM chat WHERE nickname LIKE ?";QSqlQuery sq;// 预处理sq.prepare(sql);sq.addBindValue(nickname);if (sq.exec()){bool found = false;while (sq.next()){if (!found){found = true;}// 取出一条记录中的每个字段值QString time = sq.value(0).toString();QString nickname = sq.value(1).toString();QString msg = sq.value(2).toString();output<<time<<":"<<nickname<<":"<<msg<<":"<<"end";}if (!found){qDebug() << "未查询到符合条件的记录。";output<<QString("查询失败"); //客户端接收通过“:”拆分长度为1}}else{// 获得错误细信息封装类QSqlError info = sq.lastError();// 提取错误信息QString msg = info.text();msg.prepend("查询操作失败!");QMessageBox::warning(this,"通知",msg);}
}//按消息内容查询
void Dialog::selectMsg(QString msg)
{QTextStream output(socket);// 预处理的SQLQString sql = "SELECT * FROM chat WHERE msg LIKE ?";QSqlQuery sq;// 预处理sq.prepare(sql);sq.addBindValue(msg.prepend("%").append("%")); // 通配符if (sq.exec()){bool found = false;while (sq.next()){if (!found){found = true;}// 取出一条记录中的每个字段值QString time = sq.value(0).toString();QString nickname = sq.value(1).toString();QString message = sq.value(2).toString();output<<time<<":"<<nickname<<":"<<message<<":"<<"end";}if (!found){qDebug() << "未查询到符合条件的记录。";output<<QString("查询失败");}}else{// 获得错误细信息封装类QSqlError info = sq.lastError();// 提取错误信息QString msg = info.text();msg.prepend("查询操作失败!");QMessageBox::warning(this,"通知",msg);}
}//查询全部聊天记录
void Dialog::selectAll()
{QTextStream output(socket);// 预处理QString sql = "SELECT * FROM chat";QSqlQuery sq;if (sq.exec(sql)){bool found = false;while (sq.next()){if (!found){found = true;}// 取出一条记录中的每个字段值QString time = sq.value(0).toString();QString nickname = sq.value(1).toString();QString message = sq.value(2).toString();output<<time<<":"<<nickname<<":"<<message<<":"<<"end";}if (!found){qDebug() << "未查询到符合条件的记录。";output<<QString("查询失败");}}else{// 获得错误细信息封装类QSqlError info = sq.lastError();// 提取错误信息QString msg = info.text();msg.prepend("查询操作失败!");QMessageBox::warning(this,"通知",msg);}
}//某一客户端退出
void Dialog::disconnSlot()
{socket=(QTcpSocket*)sender();for(int i=0;i<clients.size();i++){if(socket==clients.at(i)){// 拿到对面的IP地址和端口号并展示QString ip = clients.at(i)->peerAddress().toString();quint16 port = clients.at(i)->peerPort();QString text = ip.append(":") + QString::number(port);printMsg(text.append(" 已下线"));clients.removeAt(i);//及时修改在线人数ui->lineEditCount->setText(QString::number(clients.size()));}}
}
客户端
ui
cient.pro
#-------------------------------------------------
#
# Project created by QtCreator 2024-10-22T16:51:03
#
#-------------------------------------------------QT += core gui network
RC_FILE +=icon_config.rcgreaterThan(QT_MAJOR_VERSION, 4): QT += widgetsTARGET = client
TEMPLATE = appSOURCES += main.cpp\dialog.cppHEADERS += dialog.hFORMS += dialog.uiRESOURCES += \res.qrcDISTFILES += \icon_config.rc
dialog.h
#ifndef DIALOG_H
#define DIALOG_H#include <QTcpSocket> // TCP连接
#include <QMessageBox>
#include <QTextStream> // 文本流
#include <QDateTime>
#include<QPixmap>
#include<QPainter>//画家对象namespace Ui {
class Dialog;
}class Dialog : public QDialog
{Q_OBJECTpublic:explicit Dialog(QWidget *parent = 0);~Dialog();protected://创建画家对像 注意就是这个名字 发生倾斜就是对了void paintEvent(QPaintEvent *);private:Ui::Dialog *ui;QTcpSocket* client; // 客户端连接对象private slots:void btnConnClickedSlot();//连接槽函数void connectedSlot(); // 连接成功的槽函数void disconnectedSlot(); // 连接断开的槽函数void registerSlot(); //注册槽函数void loginSlot(); //登录槽函数void btnSendClickedSlot();//发送聊天信息槽函数void readyReadSlot(); //读信号槽void btnHistoryCickedSlot();//查询历史记录槽函数void onComboBoxTextChanged( QString ); //选择查询方式的槽函数void btnChagepageSlot(); //退回到第一界面槽函数void btnChagepageSlot2(); //退回到第二界面槽函数
};#endif // DIALOG_H
dialog.cpp
#include "dialog.h"
#include "ui_dialog.h"Dialog::Dialog(QWidget *parent) :QDialog(parent),ui(new Ui::Dialog)
{ui->setupUi(this);// 界面置顶setWindowFlags(Qt::WindowStaysOnTopHint);//设置默认界面ui->stackedWidget->setCurrentIndex(0);//点击连接connect(ui->pushButtonConn,SIGNAL(clicked()),this,SLOT(btnConnClickedSlot()));client = new QTcpSocket(this);// 连接状态监测信号槽connect(client,SIGNAL(connected()),this,SLOT(connectedSlot()));connect(client,SIGNAL(disconnected()),this,SLOT(disconnectedSlot()));//点击注册connect(ui->pushButtonRegister,SIGNAL(clicked()),this,SLOT(registerSlot()));//点击登录connect(ui->pushButtonLogin,SIGNAL(clicked()),this,SLOT(loginSlot()));//点击发送connect(ui->pushButtonSend,SIGNAL(clicked()),this,SLOT(btnSendClickedSlot()));//点击查询历史记录connect(ui->pushButtonHis,SIGNAL(clicked()),this,SLOT(btnHistoryCickedSlot()));//点击切换前一界面connect(ui->pushButtonEnd,SIGNAL(clicked()),this,SLOT(btnChagepageSlot()));connect(ui->pushButtonEHis,SIGNAL(clicked()),this,SLOT(btnChagepageSlot2()));
}Dialog::~Dialog()
{// 断开信号槽disconnect(client,SIGNAL(disconnected()),this,SLOT(disconnectedSlot()));// 主动断开if(client->isOpen())client->close();delete ui;
}void Dialog::paintEvent(QPaintEvent *)
{///创建画家对象/// 参数为哪儿画,继承QPaintDevice的类对象才能被绘制QPainter painter(this);//创建一个要画的图片对象QPixmap pic(":/new/prefix1/bd.jpg");//开始绘制//参数1/2:绘制的坐标;//参数3&4:绘制的宽高;//参数5:绘制的内容;painter.drawPixmap(0,0,this->width(),this->height(),pic);//使lineEdit控件透明ui->lineEditPassword->setStyleSheet("QLineEdit { background-color: transparent; }");ui->lineEdit_Id->setStyleSheet("QLineEdit { background-color: transparent; }");ui->lineEdit_IP->setStyleSheet("QLineEdit { background-color: transparent; }");ui->textBrowser->setStyleSheet("QTextBrowser { background-color: transparent; }");}
void Dialog::btnConnClickedSlot()
{// 获取用户输入的IP地址和端口号// 【升级】验证ip地址输入格式的有效性QString ip = ui->lineEdit_IP->text();if(ip==""){QMessageBox::warning(this,"提示","请输入ip!");return;}quint16 port = ui->spinBox_2->value();if(port==0){QMessageBox::warning(this,"提示","请输入端口号!");return;}// 连接到服务器client->connectToHost(ip,port);
}//连接
void Dialog::connectedSlot()
{// 屏蔽连接按键,释放发送按键ui->pushButtonConn->setEnabled(false);ui->pushButtonConn->setText("已连接");//打开读功能connect(client,SIGNAL(readyRead()),this,SLOT(readyReadSlot()));
}//断开连接
void Dialog::disconnectedSlot()
{// 释放连接按键ui->pushButtonConn->setEnabled(true);ui->pushButtonConn->setText("连接");QMessageBox::warning(this,"提示","连接已断开!");
}//读
void Dialog::readyReadSlot()
{QTextStream input(client);QString text = input.readAll();QStringList list = text.split(":");if(list.size()<4){if(text=="欢迎来到聊天室!")QMessageBox::information(this,"连接成功",text);if(text=="账号已存在")QMessageBox::warning(this,"提示","账号已存在,请重新注册!");if(text=="注册成功")QMessageBox::information(this,"成功","注册成功!请登录!!");if(text=="登录失败")QMessageBox::warning(this,"提示","用户名或密码错误!");if(text=="查询失败")QMessageBox::warning(this,"提示","查不到相关信息!");if(text=="登录成功")//切换到第二界面ui->stackedWidget->setCurrentIndex(1);//将所有用户聊天信息显示到公屏上if(list.size()==3){QString dt=list.value(0);QString nickname=list.value(1);QString msg=list.value(2);QString Msg=nickname+":"+msg;ui->textBrowser->append(dt);ui->textBrowser->append(Msg);}}else{QStringList list2 = text.split("end",QString::SkipEmptyParts);for(int j=0;j<list2.size();j++){QStringList list3 = list2.value(j).split(":");QString time=list3.value(0);QString name=list3.value(1);QString msg=list3.value(2);QString xinxi=time.append("\n").append(name).append(":").append(msg);ui->textBrowserHis->append(xinxi);}}
}//注册
void Dialog::registerSlot()
{//检查是否连接if(ui->pushButtonConn->text()=="连接"){QMessageBox::warning(this,"提示","请先连接!!!");return;}//获取输入的账号密码QString id=ui->lineEdit_Id->text();if(id == ""){QMessageBox::warning(this,"提示","请输入账号!");return;}QString password=ui->lineEditPassword->text();if(password == ""){QMessageBox::warning(this,"提示","请输入密码!");return;}//发送到服务器存入数据库QTextStream output(client);output << id<<":"<<password; //服务器接收通过“:”拆分长度为2
}
//登录
void Dialog::loginSlot()
{//检查是否连接if(ui->pushButtonConn->text()=="连接"){QMessageBox::warning(this,"提示","请先连接!!!");return;}//获取输入的账号密码QString id=ui->lineEdit_Id->text();if(id == ""){QMessageBox::warning(this,"提示","请输入账号!");return;}QString password=ui->lineEditPassword->text();if(password == ""){QMessageBox::warning(this,"提示","请输入密码!");return;}//发给服务器验证QTextStream output(client);output << id<<":"<<password<<":"<<"end"; //服务器接收通过“:”拆分长度为3
}//发送聊天消息
void Dialog::btnSendClickedSlot()
{// 获得用户输入的消息QString user = ui->lineEditUser->text();if(user == ""){QMessageBox::warning(this,"提示","请输入昵称!");return;}QString msg = ui->plainTextEdit->toPlainText();if(msg == ""){QMessageBox::warning(this,"提示","请输入消息内容!");return;}if(msg.size() > 128){QMessageBox::warning(this,"提示","消息内容过长!");return;}// 获得日期时间QString dt = QDateTime::currentDateTime().toString("yyyy-MM-dd hh:mm");// TODO 给服务器发信息QTextStream output(client);output << dt<<":"<<user<<":" << msg<<":"<<"end"; //服务器接收通过“:”拆分长度为4QString xinxi=dt.append("\n").append(user).append("(本机):").append(msg);ui->textBrowser->append(xinxi);ui->plainTextEdit->clear();
}//查询历史记录
void Dialog::btnHistoryCickedSlot()
{//切换为第三页面ui->stackedWidget->setCurrentIndex(2);//选择查询类型connect(ui->comboBox, SIGNAL(activated(QString)),this, SLOT(onComboBoxTextChanged(QString)));
}//查询类型的槽函数
void Dialog::onComboBoxTextChanged(QString text)
{//清空上一次查询的内容ui->textBrowserHis->clear();;//建立写通道QTextStream output(client);if(text=="查询所有聊天记录"){output<<text; //服务器接收通过“:”拆分长度为1}else{//获取查询的内容QString msg=ui->plainTextEditHis->toPlainText();if(msg==""){QMessageBox::warning(this,"提示","请输入查询内容!");return;}output<<text<<":"<<msg<<":"<<"end"; //服务器接收通过“:”拆分长度为3}
}
//切换到第一界面
void Dialog::btnChagepageSlot()
{ui->stackedWidget->setCurrentIndex(0);
}
//切换到第二界面
void Dialog::btnChagepageSlot2()
{ui->stackedWidget->setCurrentIndex(1);
}
打包步骤不做演示
视频演示
http://【Qt聊天室】 https://www.bilibili.com/video/BV1uW1MYbEZz/?share_source=copy_web&vd_source=989c862553a9fc170dee4fdcac7a0592http://【Qt聊天室】 https://www.bilibili.com/video/BV1uW1MYbEZz/?share_source=copy_web&vd_source=989c862553a9fc170dee4fdcac7a0592
————源码已上传