一、设计要求
用QT做一个聊天室,
制作一个服务器和客户端。可以进行注册、登录,
登陆成功后可以使用昵称进行发送、接收消息。
能根据昵称、聊天内容查询历史记录,也可以查询全部聊天记录。
。
二、客户端三级ui界面
三、项目代码
//在pro文件里加入
QT += core gui network
RC_FILE += icon_config.rc
//客户端dialog.h
#ifndef DIALOG_H
#define DIALOG_H
#include <QtWidgets>
#include <QDebug>
// 网络连接类
#include <QTcpSocket>
// 文本流
#include <QTextStream>
#include <QDateTime>
#include <QByteArray>
namespace Ui {
class Dialog;
}
class Dialog : public QDialog
{
Q_OBJECT
public:
explicit Dialog(QWidget *parent = 0);
~Dialog();
private:
Ui::Dialog *ui;
QTcpSocket *client;
void printMsg(QString); // 输出内容到公屏
void succRight();
private slots:
void btnConnClickedSlot(); // 连接按钮
void btnSendClickedSlot(); // 发送按钮
void connectedSlot(); // 连接成功的槽函数
void disconnectedSlot(); // 断开连接的槽函数
void readReadSlot(); // 接收数据的槽函数
void btnHisClickedSlot();//历史记录
void btnHisNameClickedSlot();//按照昵称
void btnHisNeiClickedSlot();//按照内容
void btnLoginClickedSlot();//登录/切换窗口
void btnRegClickedSlot();//注册
};
#endif // DIALOG_H
//客户端dialog.c
#include "dialog.h"
#include "ui_dialog.h"
Dialog::Dialog(QWidget *parent) :
QDialog(parent),
ui(new Ui::Dialog)
{
ui->setupUi(this);
// 抢前台
setWindowFlags(Qt::WindowStaysOnTopHint);
connect(ui->pushButtonConn,SIGNAL(clicked()),
this,SLOT(btnConnClickedSlot()));
connect(ui->pushButtonSend,SIGNAL(clicked()),
this,SLOT(btnSendClickedSlot()));
client = new QTcpSocket(this);
// 建立网络连接检测的信号槽
connect(client,SIGNAL(connected()),
this,SLOT(connectedSlot()));
connect(client,SIGNAL(disconnected()),
this,SLOT(disconnectedSlot()));
// 接收消息的信号槽
connect(client,SIGNAL(readyRead()),
this,SLOT(readReadSlot()));
//历史
connect(ui->pushButtonHis,SIGNAL(clicked()),
this,SLOT(btnHisClickedSlot()));
connect(ui->pushButtonName,SIGNAL(clicked()),
this,SLOT(btnHisNameClickedSlot()));
connect(ui->pushButtonNei,SIGNAL(clicked()),
this,SLOT(btnHisNeiClickedSlot()));
//切换窗口:登录
connect(ui->pushButtonLo,SIGNAL(clicked()),
this,SLOT(btnLoginClickedSlot()));
//注册
connect(ui->pushButtonReg,SIGNAL(clicked()),
this,SLOT(btnRegClickedSlot()));
}
Dialog::~Dialog()
{
disconnect(client,SIGNAL(disconnected()),
this,SLOT(disconnectedSlot()));
// 如果还在连接
if(client->isOpen())
client->close();
delete ui;
}
void Dialog::btnConnClickedSlot()
{
// 发起连接请求
// 默认用户输入的参数都对
client->connectToHost(ui->lineEditIp->text(),ui->spinBox->value());
}
void Dialog::printMsg(QString msg)
{
// 获得当前时间
QString time = QDateTime::currentDateTime().toString("yyyy-MM-dd-hh:mm:ss");
ui->textBrowser->append(time);
ui->textBrowser->append(msg);
ui->textBrowser->append("");
}
void Dialog::succRight()
{
ui->stackedWidget->setCurrentIndex(1);
}
void Dialog::btnSendClickedSlot()
{
// 获得昵称和消息内容
QString user = ui->lineEditUser->text();
if(user=="")
{
QMessageBox::warning(this,"提示","请输入昵称!");
return;
}
QString msg = ui->lineEditMsg->text();
if(msg == "")
{
QMessageBox::warning(this,"提示","请输入要发送的消息!");
return;
}
QString time = QDateTime::currentDateTime().toString("yyyy-MM-dd-hh-mm-ss");
// 创建文本流对象
QTextStream output(client);
// 连续输出发送
output << time<<":"<<user << ":" << msg;
// 清空消息输入框
ui->lineEditMsg->clear();
// 公屏显示
msg = user+QString("(本机):")+msg;
printMsg(msg);
}
void Dialog::connectedSlot()
{
// 屏蔽连接按钮,开启发送按钮
ui->pushButtonConn->setEnabled(false);
ui->pushButtonConn->setText("已连接");
ui->pushButtonSend->setEnabled(true);
ui->stackedWidget->setCurrentIndex(1);
}
void Dialog::readReadSlot()
{
QTextStream input(client);
QString text = input.readAll();
QString text1=input.readLine(100);
qDebug() <<text1;
QStringList list = text.split(":");
QStringList list2 = text1.split(":");
qDebug()<<"分割后数量"<<list.size();
qDebug() <<list2.size();
if(list.size()<4)
{
if(text=="dlchengg")
{
qDebug() <<text;
ui->stackedWidget->setCurrentIndex(2);
ui->textBrowser->clear();
}
// else if(list.size()==3)
// {
// ui->textBrowser_2->append(text);
// return;
// }
else
{
printMsg(text);
}
}
else if(list.size()>=4)
{
ui->textBrowser_2->append(text);
return;
}
}
void Dialog::btnHisClickedSlot()
{
ui->textBrowser_2->clear();
QString user = ui->lineEditUser->text();
if(user=="")
{
QMessageBox::warning(this,"提示","请输入昵称!");
return;
}
QString time = QDateTime::currentDateTime().toString("yyyy-MM-dd-hh-mm-ss");
// 创建文本流对象
QTextStream output(client);
QString mm="历史记录";
output<< time<<":"<<user << ":" <<mm ;
}
void Dialog::btnHisNameClickedSlot()
{
ui->textBrowser_2->clear();
QString user = ui->lineEditUser->text();
QString time = "hh";
// 创建文本流对象
QTextStream output(client);
QString mm="按照昵称";
output<< time<<":"<<user << ":" <<mm ;
}
void Dialog::btnHisNeiClickedSlot()
{
ui->textBrowser_2->clear();
QString user = "sjdhs";
QString time = "按照内容";
// 创建文本流对象
QString msg = ui->lineEditMsg->text();
if(msg == "")
{
QMessageBox::warning(this,"提示","请输入要发送的消息!");
return;
}
QTextStream output(client);
output<< time<<":"<<user << ":" <<msg ;
}
void Dialog::btnLoginClickedSlot()
{
QString user = ui->lineEditUs->text();
if(user=="")
{
QMessageBox::warning(this,"提示","请输入昵称!");
return;
}
QString pwd = ui->lineEdit_2Pwd->text();
if(pwd == "")
{
QMessageBox::warning(this,"提示","请输入密码!");
return;
}
// 创建文本流对象
QTextStream output(client);
// 连续输出发送
QString mag="hha";
QString haf="lele";
output <<user << ":" << pwd<<":"<<mag<<":"<<haf;
}
void Dialog::btnRegClickedSlot()
{
QString user = ui->lineEditUs->text();
if(user=="")
{
QMessageBox::warning(this,"提示","请输入昵称!");
return;
}
QString pwd = ui->lineEdit_2Pwd->text();
if(pwd == "")
{
QMessageBox::warning(this,"提示","请输入密码!");
return;
}
// 创建文本流对象
QTextStream output(client);
// 连续输出发送
output <<user << ":" << pwd;
}
void Dialog::disconnectedSlot()
{
// 开启连接按钮,屏蔽发送按钮
ui->pushButtonConn->setEnabled(true);
ui->pushButtonConn->setText("连接");
ui->pushButtonSend->setEnabled(false);
// 弹窗
printMsg("连接已断开!");
QMessageBox::warning(this,"提示","连接已断开!");
ui->stackedWidget->setCurrentIndex(0);
}
//服务器dialog.h
#ifndef DIALOG_H
#define DIALOG_H
#include <QtWidgets>
#include <QDebug>
// 连接管理类
#include <QTcpServer>
#include <QDateTime>
// 连接类
#include <QTcpSocket>
// 文本流
#include <QTextStream>
#include <QButtonGroup>
#include <QSqlDatabase>
#include <QDebug>
#include <QSqlError>
#include <QMessageBox>
#include <QSqlQuery>
#include <QByteArray>
namespace Ui {
class Dialog;
}
class Dialog : public QDialog
{
Q_OBJECT
public:
explicit Dialog(QWidget *parent = 0);
~Dialog();
private:
Ui::Dialog *ui;
QTcpServer* server; // 管理对象(母鸡)
void printMsg(QString); // 输出内容到公屏
QTcpSocket* socket = NULL; // 连接对象(绿蛋)
QList<QTcpSocket*> sockets;
QList<QString> ips;
QSqlDatabase db;
void connect2DB(); // 连接到数据库1
void createTable();// 建表
void createTable2();
void insertData(); // 插入数据
void selectAll(int); // 数据全查
void selectLOgin(QString,QString,int);
void selectName(QString,int);
void selectNei(QString,int);
private slots:
// 新连接来了的槽函数
void newConnSlot();
// 连接掉线的信号槽
void disconnetedSlot();
// 有数据可读时的槽函数
void readyReadSlot();
};
#endif // DIALOG_H
//服务器dialog.c
#include "dialog.h"
#include "ui_dialog.h"
Dialog::Dialog(QWidget *parent) :
QDialog(parent),
ui(new Ui::Dialog)
{
ui->setupUi(this);
// 抢前台
setWindowFlags(Qt::WindowStaysOnTopHint);
server = new QTcpServer(this);
// 连接新连接来了的信号槽
connect(server,SIGNAL(newConnection()),
this,SLOT(newConnSlot()));
// 开启监听服务
server->listen(QHostAddress::Any,8887);
connect2DB();
}
Dialog::~Dialog()
{
if(server->isListening()) // 如果还在监听
server->close();
delete ui;
}
void Dialog::printMsg(QString msg)
{
// 获得当前时间
QString time = QDateTime::currentDateTime().toString("yyyy-MM-dd hh:mm:ss");
ui->textBrowser->append(time);
ui->textBrowser->append(msg);
ui->textBrowser->append("");
}
void Dialog::connect2DB()
{
// 创建连接对象
db = QSqlDatabase::addDatabase("QSQLITE");
// 设置数据库的文件名称
db.setDatabaseName("book_management.db");
// 打开数据库
if(db.open())
{
qDebug() << "连接成功";
// createTable();
// createTable2();
}
else
{
// 获得错误信息封装类
QSqlError info = db.lastError();
// 提取错误文本
QString text = info.text();
// 展示错误
QMessageBox::critical(this,"错误",text);
}
}
void Dialog::createTable()
{
QString sql = "CREATE TABLE book(time TEXT PRIMARY KEY,name TEXT,msg TEXT);";
// 创建数据库操作类对象
QSqlQuery sq;
if(sq.exec(sql))
{
qDebug() << "建表成功";
}else// 失败
{
// 获得错误信息封装类
QSqlError info = sq.lastError();
// 提取错误文本
QString text = info.text();
// 展示错误
qDebug() << text;
}
}
void Dialog::createTable2()
{
QString sql2 = "CREATE TABLE class(name TEXT PRIMARY KEY,pwd TEXT);";
// 创建数据库操作类对象
QSqlQuery sq;
if(sq.exec(sql2))
{
qDebug() << "建表2成功";
}else// 失败
{
// 获得错误信息封装类
QSqlError info = sq.lastError();
// 提取错误文本
QString text = info.text();
// 展示错误
qDebug() << text;
}
}
void Dialog::selectAll(int i)
{
QString sql = "SELECT * FROM book";
QSqlQuery sq;
sq.prepare(sql);
if(sq.exec(sql))
{
// 清空上次显示
// ui->textBrowser->clear();
while(sq.next())// 循环取出
{
// 取出一条数据库中的字段
QString time = sq.value(0).toString();
QString name = sq.value(1).toString();
QString msg = sq.value(2).toString();
QString msa="历史";
// 拼接并显示
QString text = msa.append(":")+ time.append(":")+ name.append(":") + msg;
QTextStream output(sockets.at(i));
output<< text<<endl;
}
}
}
void Dialog::selectLOgin(QString user, QString pwd2,int i)
{
QString name=user;
QString pwd=pwd2;
QString sql = "SELECT * FROM class WHERE name LIKE ? AND pwd LIKE ?;";
QSqlQuery sq;
sq.prepare(sql);
if(sq.exec(sql))
{
while(sq.next())
{
qDebug() << "yes";
QString user = sq.value(0).toString();
QString pwd = sq.value(1).toString();
QString text ="dlchengg";
QTextStream output(sockets.at(i));
output<<text;
}
}
else
{
QSqlError info = sq.lastError();
// 提取错误文本
QString text = info.text();
text.prepend("登录失败:");
QMessageBox::warning(this,"警告",text);
}
}
void Dialog::selectName(QString name1,int i)
{
QString name=name1;
QString sql = "SELECT * FROM book WHERE name LIKE ?";
QSqlQuery sq;
sq.prepare(sql);
sq.addBindValue(name);
if(sq.exec())
{
while(sq.next())// 循环取出
{
// 取出一条数据库中的字段
QString time = sq.value(0).toString();
QString name = sq.value(1).toString();
QString msg = sq.value(2).toString();
QString msa="历史";
// 拼接并显示
QString text = msa.append(":")+time.append(":")+ name.append(":") + msg;
QTextStream output(sockets.at(i));
output<< text<<endl;
}
}
}
void Dialog::selectNei(QString msg, int i)
{
QString sql = "SELECT * FROM book WHERE msg LIKE ?";
QSqlQuery sq;
sq.prepare(sql);
sq.addBindValue(msg.prepend("%").append("%"));
if(sq.exec())
{
while(sq.next())// 循环取出
{
// 取出一条数据库中的字段
QString time = sq.value(0).toString();
QString name = sq.value(1).toString();
QString msg = sq.value(2).toString();
QString msa="历史";
// 拼接并显示
QString text = msa.append(":")+time.append(":")+ name.append(":") + msg;
QTextStream output(sockets.at(i));
output<< text<<endl;
}
}
}
void Dialog::newConnSlot()
{
// 获得服务器端的连接类对象
socket = server->nextPendingConnection();
QTextStream output(socket);
// 如果满员则踢出
if(sockets.size() == 20)
{
qDebug() << "聊天室满员";
output << QString("聊天室已达人数上限,连接失败!");
socket->close();
return;
}
sockets.append(socket);
// 绿蛋收到消息的信号槽
connect(socket,SIGNAL(readyRead()),
this,SLOT(readyReadSlot()));
// 绿蛋掉线的信号槽
connect(socket,SIGNAL(disconnected()),
this,SLOT(disconnetedSlot()));
// 给客户端打个招呼
output << QString("服务器:你好啊!");
// 获得对面的IP地址和端口号
QString ip = socket->peerAddress().toString();
quint16 port = socket->peerPort();
QString portText = QString::number(port);
QString text = "新连接来了!";
text.append(ip).append(":").append(portText);
printMsg(text);
}
void Dialog::disconnetedSlot()
{
// 拿到发射者
socket = (QTcpSocket*)sender();
for(int i = 0;i<sockets.size();i++)
{
if(socket == sockets.at(i))
{
qDebug() << "第" << i << "个客户端掉线了";
// 获得对面的IP地址和端口号
QString ip = sockets.at(i)->peerAddress().toString();
quint16 port = sockets.at(i)->peerPort();
QString portText = QString::number(port);
QString text = "连接已断开!";
text.append(ip).append(":").append(portText);
printMsg(text);
sockets.removeAt(i);
}
}
}
//接收数据
void Dialog::readyReadSlot()
{
for(int i=0;i<sockets.size();i++)
{
if(sockets.at(i)->isReadable() && sockets.at(i)->bytesAvailable()>0)
{
qDebug() << "第" << i << "个客户端发的消息";
QTextStream input(sockets.at(i));
// 一口气都读了
QString text = input.readAll();
//写入数据库
QStringList list = text.split(":");
qDebug()<<"分割后数量"<<list.size();
if(list.size()==3)
{
QString time = list[0];
QString name = list[1];
QString msg = list[2];
if(list[2]=="历史记录")
{
selectAll( i);
}
else if(list[2]=="按照昵称")
{
selectName(name,i);
}
else if(list[0]=="按照内容")
{
selectNei(msg,i);
}
else
{
createTable();
QString sql = "INSERT INTO book VALUES(?,?,?);";
QSqlQuery sq;
sq.prepare(sql);
sq.addBindValue(time);
sq.addBindValue(name);
sq.addBindValue(msg);
if(sq.exec())
{
qDebug()<<"数据插入成功";
// QMessageBox::information(this,"通知","数据插入成功");
}
else
{
// 获得错误信息封装类
QSqlError info = sq.lastError();
// 提取错误文本
QString text = info.text();
// 展示错误
text.prepend("数据插入失败:");
QMessageBox::warning(this,"警告",text);
}
printMsg(text);
for(int m=0;m<sockets.size();m++)
{
if(m==i)
continue;
QTextStream output(sockets.at(m));
output << text;
}
}
}
else if(list.size()==2)
{
createTable2();
QString name = list[0];
QString pwd = list[1];
QString sql = "INSERT INTO class VALUES(?,?);";
QSqlQuery sq;
sq.prepare(sql);
sq.addBindValue(name);
sq.addBindValue(pwd);
if(sq.exec())
{
qDebug()<<"注册成功";
// QMessageBox::information(this,"通知","数据插入成功");
}
else
{
// 获得错误信息封装类
QSqlError info = sq.lastError();
// 提取错误文本
QString text = info.text();
// 展示错误
text.prepend("注册失败:");
QMessageBox::warning(this,"警告",text);
}
printMsg(text);
for(int m=0;m<sockets.size();m++)
{
if(m==i)
continue;
QTextStream output(sockets.at(m));
output << text;
}
}
else if(list.size()==4)
{
QString name = list[0];
QString pwd = list[1];
qDebug() << name<<pwd;
QString sql = "SELECT * FROM class WHERE name=? AND pwd=?";
QSqlQuery sq;
sq.prepare(sql);
sq.addBindValue(name);
sq.addBindValue(pwd);
qDebug() << "yes";
if(sq.exec())
{
// 取出一条数据库中的字段
while(sq.next())
{
QString name = sq.value(0).toString();
QString pwd = sq.value(1).toString();
qDebug() <<name<<pwd;
qDebug() << "yes";
QString text ="dlchengg";
QTextStream output(sockets.at(i));
output<<text;
}
}
else
{
QSqlError info = sq.lastError();
// 提取错误文本
QString text = info.text();
text.prepend("登录失败:");
QMessageBox::warning(this,"警告",text);
}
}
}
}
}