功能
● 支持多客户端群聊功能
● 支持聊天记录保存功能,可以进行查询
● 美化样式
● 打包
● 人脸检测
● 用户登录
● 头像
客户端代码
login.h
#ifndef LOGIN_H
#define LOGIN_H
#include <QDialog>
#include<QDebug>
#include<QPixmap>
#include<QPainter>//画家对象
#include"dialog.h"
#include<QMessageBox>
#include<QTcpSocket>//创建客户端对象
#include<QSqlQuery>//数据库操作类
#include<QSqlDatabase>//数据库连接对象
#include<QSqlError>//数据库错误
#include <QTimer>
#include <QImage>
#include <vector>
using namespace std;
#include <opencv2/opencv.hpp> // CV基础功能
using namespace cv;
#include <opencv2/face.hpp> // 人脸检测
using namespace cv::face;
namespace Ui {
class Login;
}
class Login : public QDialog
{
Q_OBJECT
public:
explicit Login(QWidget *parent = 0);
~Login();
protected:
//创建画家对像 注意就是这个名字 发生倾斜就是对了
void paintEvent(QPaintEvent *event);
private:
Ui::Login *ui;
Dialog *aa;
QString ip;
int port;
QTcpSocket *client;//客户端连接对象
QSqlDatabase db;//数据库连接对象,栈内存
void connetSql();//连接到数据库函数
void creatTable();//建表函数
bool isDataExist(QString);//判断某个id的数据在
bool notDataExist(QString);//判断某个id的数据不在
CascadeClassifier classifier; // 级联分类器:进行人脸比对
VideoCapture vc; // 存储摄像头数据
QTimer *timer; // 定时器
Mat src; // 存储图像的矩阵对象
// 正中间 300x300的矩形数据(有效识别区域)
Rect r;
// 使用一个向量对象存储人脸矩形
vector<Rect> vec_findfaces;
void blackSrc();
void findFace();
void showSrc();
void startCarmer();//启动摄像头
void faceStart(int);//检测到人脸,直接登录
//定义人脸数量
int facenume=0;
private slots:
void connectSlot();//登录按钮的槽函数
// void netSuccessSlot();//连接成功的槽函数
// void errorSlot();//连接失败的槽函数
// void readyReaSLot();// //读取服务器发的消息
void registerSlot();//注册按钮
void timeoutSlot(); // 定时器到点了的槽函数
void carmerSlot();//启动摄像头槽函数
void disconnectSlot();//断开网络的槽函数
};
#endif // LOGIN_H
login.cpp
#include "login.h"
#include "ui_login.h"
Login::Login(QWidget *parent) :
QDialog(parent),
ui(new Ui::Login)
{
ui->setupUi(this);
//创建客户端连接的对象
client=new QTcpSocket;
//连接按钮
connect(ui->pushButton,SIGNAL(clicked()),this,SLOT(connectSlot()));
//注册按钮
connect(ui->pushButtonRegister,SIGNAL(clicked()),this,SLOT(registerSlot()));
// // 连接成功信号
// connect(client,SIGNAL(connected()),this,SLOT(netSuccessSlot()));
// //连接失败
// connect(client,SIGNAL(error(QAbstractSocket::SocketError)),this,SLOT(errorSlot()));
//调用数据库函数
connetSql();
//摄像头组件透明
ui->labelCarer->setStyleSheet("QLabel { background-color: transparent; }");
// 初始化级联分类器,加载人脸数据模型
classifier = CascadeClassifier("D:/opencv/opencv3.4-install/install/etc/haarcascades/haarcascade_frontalface_alt2.xml");
//人脸识别按钮
connect(ui->pushButtonCarer,SIGNAL(clicked()),this,SLOT(carmerSlot()));
}
Login::~Login()
{
if(db.isOpen())
db.close();
if(timer->isActive())
timer->stop();
qDebug()<<"已经销毁第一个界面";
delete ui;
}
void Login::paintEvent(QPaintEvent *event)
{
///创建画家对象
/// 参数为哪儿画,继承QPaintDevice的类对象才能被绘制
QPainter painter(this);
//创建一个要画的图片对象
QPixmap pic(":/new/prefix1/img/11.jpg");
//开始绘制
//参数1/2:绘制的坐标;
//参数3&4:绘制的宽高;
//参数5:绘制的内容;
painter.drawPixmap(0,0,this->width(),this->height(),pic);
//使lineEdit控件透明
ui->lineEditPassword->setStyleSheet("QLineEdit { background-color: transparent; }");
ui->lineEditId->setStyleSheet("QLineEdit { background-color: transparent; }");
ui->lineEditIP->setStyleSheet("QLineEdit { background-color: transparent; }");
}
/**
* @brief Login::connetSql 连接数据库
*/
void Login::connetSql()
{
//获取数据库连接对像 改变这个对像会出错
db=QSqlDatabase::addDatabase("QSQLITE");
//设置数据库文件名称 .db .db3 pasture牧场
db.setDatabaseName("chat_qq.db");
///连接到数据库
if(db.open())
{
qDebug()<<"数据库连接成功";
//建表
creatTable();
}
else
{
//获取错误信息,展示·给用户
QSqlError err=db.lastError();
//转为text文本 便于显示
QString text=err.text();
//往前追加错误信息
text.prepend("连接错误! ");
//输出错误信息
QMessageBox::critical(this,"错误",text);
}
}
/**
* @brief Login::creatTable 建表
*/
void Login::creatTable()
{
// 字符串内部换行使用'\'
QString sql = "CREATE TABLE qq(\
id INTEGER PRIMARY KEY,\
password INT\
);\
";
//创建一个数据库操作类对象
QSqlQuery sq;
///执行SQL语句
if(sq.exec(sql))
{
qDebug()<<"建表成功";
}
else
{
//输出错误信息
QString text=sq.lastError().text();
qDebug()<<"建表失败 "<<text;
}
}
//登录
void Login::connectSlot()
{
qDebug()<<"正在登录";
//拿到信息
QString id=ui->lineEditId->text();
QString pass=ui->lineEditPassword->text();
ip=ui->lineEditIP->text();
port=ui->spinBox->value();
qDebug()<<"这是登录的"<<ip<<port;
//创建子界面
aa=new Dialog(ip,port);//构造函数传参
//开始进行遍历表
if(id==""||pass=="")
{
QMessageBox::warning(this,"警告","输入账号和密码!");
//清空账号和密码
ui->lineEditId->clear();
ui->lineEditPassword->clear();
//把光标移动到输入账号中
ui->lineEditId->setFocus();
return ;
}
if(!isDataExist(id))
{
QMessageBox::warning(this,"提示","账号不存在,请注册");
return ;
}
qDebug()<<"我在往下";
//在查找密码
QString sql = "SELECT * FROM qq WHERE id =:id AND password =:pass";
//执行操作类
QSqlQuery sq;
sq.prepare(sql);
//必须按照上面的预处理语句中的?顺序
sq.addBindValue(id);
sq.addBindValue(pass);
if(sq.exec())
{
qDebug()<<"我在查询了已经";
if(sq.next())
{
qDebug()<<"已经查询到了!";
this->close();
aa->show();
}
else
{
//获取错误信息
QMessageBox::information(this,"提示","密码错误!!");
//清空账号和密码
ui->lineEditId->clear();
ui->lineEditPassword->clear();
//把光标移动到输入账号中
ui->lineEditId->setFocus();
}
}
else
{
QString text=sq.lastError().text().prepend("查找失败");
QMessageBox::critical(this,"错误",text);
}
}
//注册
void Login::registerSlot()
{
//获取用户输入
QString id=ui->lineEditId->text();
QString password=ui->lineEditPassword->text();
//判读用户是否输入
if(id==""||password=="")
{
QMessageBox::information(this,"提示","您没有正确输入");
return;
}
//插入
//预处理的SQL语句
QString sql="INSERT INTO qq VALUES(:id,:password);";
//数据库操作
QSqlQuery sq;
//预处理
sq.prepare(sql);
//参数绑定(Oracle风格可以乱序)
//注意上面的定义与之对应
sq.bindValue(":id",id);
sq.bindValue(":password",password);
if(sq.exec())
{
QMessageBox::information(this,"通知","注册成功");
}
else
{
//展示错误信息
QSqlError err=db.lastError();
QString text=err.text();
text.prepend("注册失败,账号已经存在!!");
//清空账号和密码
ui->lineEditId->clear();
ui->lineEditPassword->clear();
//把光标移动到输入账号中
ui->lineEditId->setFocus();
QMessageBox::critical(this,"错误",text);
}
}
/**
* @brief Dialog::isDataExist 判断某个数据在不在
* @param id
* @return 数据是否存在
*/
用于上面的判断
bool Login::isDataExist(QString id)
{
QString sql="SELECT * FROM qq WHERE id=";
sql.append(id);
QSqlQuery sq;
if(sq.exec(sql))
return sq.next();
return false;
}
//人脸识别
/**
* @brief Dialog::blackSrc
* 标记人脸检测有效区域
*/
void Login::blackSrc()
{
int rectSize = 300;
// 有效区域的坐标
int x = src.cols/2 - rectSize/2;
int y = src.rows/2 - rectSize/2;
// 矩形对象
r = Rect(Point(x,y),Size(rectSize,rectSize));
// 画框
rectangle(src,r,Scalar(255,255,255));
// 遍历列
for(int x = 0;x<src.cols;x++)
{
// 每一行
for(int y = 0;y<src.rows;y++)
{
// 判断当前像素点是否不在矩形中
if(!r.contains(Point(x,y)))
{
// 周围变暗
Vec3b& v = src.at<Vec3b>(Point(x,y));
v[0] = saturate_cast<uchar>(v[0]-50);
v[1] = saturate_cast<uchar>(v[1]-50);
v[2] = saturate_cast<uchar>(v[2]-50);
}
}
}
}
void Login::findFace()
{
// 使用一个矩阵存储灰度图像,可以提升处理速度
Mat gray;
// 从原始图像中扣出300x300小图
Mat midSrc = src(r);
// BGR → GRAY
cvtColor(midSrc,gray,CV_BGR2GRAY);
qDebug() << "灰度图是否为空:" << gray.empty();
// 使用级联分类器在绘图中找人脸,这些人脸的数据存在向量中
classifier.detectMultiScale(gray,vec_findfaces);
// 如果有人脸就画红框
if(vec_findfaces.size() > 0)
{
facenume=vec_findfaces.size();
//传人脸数量
faceStart(facenume);
qDebug() << "人脸数量:" << vec_findfaces.size();
for(int i=0;i<vec_findfaces.size();i++)
{
// 取出每张人脸的矩形数据
Rect faceRect = vec_findfaces.at(i);
// 画框
rectangle(midSrc,faceRect,Scalar(0,0,255),2);
}
}
}
/**
* @brief Dialog::showSrc
* 在Qt界面上显示
*/
void Login::showSrc()
{
// BGR → RGB
Mat rgb;
cvtColor(src,rgb,CV_BGR2RGB);
// Mat → QImage(Qt的图像计算类)
QImage img(rgb.data, // 数据来源
rgb.cols, // 宽度
rgb.rows, // 高度
rgb.cols*rgb.channels(), // 每一行的总通道数
QImage::Format_RGB888 // 每个通道的深度 0-255 2^8
);
// QImage → QPixmap
QPixmap pic = QPixmap::fromImage(img);
// 设置给组件
ui->labelCarer->setPixmap(pic);
ui->labelCarer->resize(pic.width(),pic.height());
}
//启动摄像头
void Login::startCarmer()
{
// 打开摄像头
if(vc.open(0)) // 打开第一个摄像头
{
qDebug() << "摄像头打开成功!";
timer = new QTimer(this);
timer->setSingleShot(false);
timer->setInterval(50); // 20帧
connect(timer,SIGNAL(timeout()),this,SLOT(timeoutSlot()));
timer->start();
}
}
void Login::timeoutSlot()
{
// 1. 提取一张图片
vc >> src;
if(!src.empty())
qDebug() << "采集到数据!";
else
{
qDebug() << "图像采集失败!";
return;
}
// 2. 选取检测有效区域
blackSrc();
// 3. 查找人脸
findFace();
// 4. 显示图像
showSrc();
}
//启动摄像头槽函数
void Login::carmerSlot()
{
qDebug()<<"按钮已经再按";
///执行摄像头函数
faceStart(facenume);
}
//断卡网络的槽函数
void Login::disconnectSlot()
{
qDebug()<<"网络已断开";
}
void Login::faceStart(int facenume)
{
// qDebug()<<"人脸数量"<<c;
ip=ui->lineEditIP->text();
port=ui->spinBox->value();
aa=new Dialog(ip,port);//构造函数传参
startCarmer();//调用启动摄像头函数
//如果数量大于等于1,直接登录
if(facenume==1)
{
if (timer)
timer->stop();
vc.release(); //关闭摄像头的
// 清除QLabel的内容
ui->labelCarer->clear(); // 或者
ui->labelCarer->setPixmap(QPixmap());
this->close();
aa->show();
// 如果需要,你还可以调整QLabel的大小或将其隐藏
ui->labelCarer->resize(QSize(0, 0)); // 设置为一个很小的大小,或者
ui->labelCarer->hide(); // 直接隐藏
return;
}
}
main函数
#include "login.h"
#include <QApplication>
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
Login w;
w.show();
return a.exec();
}
#ifndef DIALOG_H
#define DIALOG_H
#include <QDialog>
#include<QDebug>
#include<QTcpSocket>
#include "ui_dialog.h"
#include<QDateTime>
#include<QTextStream>//文本流
#include<QMessageBox>
#include<QList>
#include<QTcpSocket>
#include<QPlainTextEdit>
#include<QPixmap>
#include<QPainter>//画家对象
#include<QTimer>
namespace Ui {
class Dialog;
}
class Dialog : public QDialog
{
Q_OBJECT
public:
explicit Dialog(QString ,int ,QWidget *parent = 0);
~Dialog();
QString ip;
int port;
protected:
//创建画家对像 注意就是这个名字 发生倾斜就是对了
void paintEvent(QPaintEvent *event);
private:
Ui::Dialog *ui;
QTcpSocket *client=NULL;//客户端连接对象
// 保存所有的连接(qt项目自行实现)
QList<QTcpSocket*>clientList;
//新连接,只保留最新的连接
void showMesg(QString);//显示信息的函数
//头像
QList<QString> list;///图片路径
QTimer *timer;
void randimg();//随机头像
private slots:
void connectSlot();//连接的槽函数
void btnSendSlot();//发送信息的槽函数
void readReSLot();//读信息的槽函数
void disconnectedSlot();//断开连接的按钮槽函数
void netSuccessSlot();//连接成功的槽函数
void errorSlot();//连接失败的槽函数
void historySlot();//查询历史记录按钮
};
#endif // DIALOG_H
dialog.cpp
#include "dialog.h"
#include "ui_dialog.h"
Dialog::Dialog(QString ip,int port,QWidget *parent) :
QDialog(parent),
ui(new Ui::Dialog)
{
ui->setupUi(this);
this->ip=ip;
this->port=port;
qDebug()<<ip<<" 我已经接收到上一个界面的消息!!这是客户端的"<<port;
//存放图片
QString img1(":/new/prefix1/img/卡通头像.png");
QString img2(":/new/prefix1/img/头像 女孩.png");
QString img3(":/new/prefix1/img/猪.png");
QString img4(":/new/prefix1/img/白领.png");
QString img5(":/new/prefix1/img/群组.png");
QString img6(":/new/prefix1/img/鸡.png");
list<<img1<<img2<<img3<<img4<<img5<<img6;
timer = new QTimer(this);
// ///放置图片至界面显示
// ui->label->setPixmap(list.at(0));
//不让它直接显示
timer->setSingleShot(false);
///1000毫秒后显示 延时1000毫秒的时候在显示
timer->setInterval(1000);
randimg();
//创建客户端对象
client =new QTcpSocket(this);
client->connectToHost(ip,port);
//发送信息按钮
connect(ui->pushButton,SIGNAL(clicked()),this,SLOT(btnSendSlot()));
//历史记录查询按钮
connect(ui->pushButtonChat,SIGNAL(clicked()),SLOT(historySlot()));
//退出按钮
connect(ui->pushButtonEnd,SIGNAL(clicked()),this,SLOT(disconnectedSlot()));
// connect(client,SIGNAL(connected()),this,SLOT(connectSlot()));
// 连接成功信号
connect(client,SIGNAL(connected()),this,SLOT(netSuccessSlot()));
//连接失败
connect(client,SIGNAL(error(QAbstractSocket::SocketError)),this,SLOT(errorSlot()));
connect(client,SIGNAL(readyRead()),this,SLOT(readReSLot()));
}
///随机播放一个图片
void Dialog::randimg()
{
qint64 time=QDateTime::currentMSecsSinceEpoch();
timer->start();
qsrand(time);
int rand=qrand()%list.size();
ui->label->setPixmap(list.at(rand));
qDebug()<<rand;
}
void Dialog::paintEvent(QPaintEvent *event)
{
///创建画家对象
/// 参数为哪儿画,继承QPaintDevice的类对象才能被绘制
QPainter painter(this);
//创建一个要画的图片对象
QPixmap pic(":/new/prefix1/img/5133.jpg");
//开始绘制
//参数1/2:绘制的坐标;
//参数3&4:绘制的宽高;
//参数5:绘制的内容;
painter.drawPixmap(0,0,this->width(),this->height(),pic);
// 设置QTextBrowser的背景为透明
ui->textBrowser->setStyleSheet("QTextBrowser { background-color: transparent; }");
ui->lineEditName->setStyleSheet("QLineEdit { background-color: transparent; }");
ui->pushButtonEnd->setStyleSheet("QPushButton { background-color: transparent; }");
ui->pushButtonChat->setStyleSheet("QPushButton { background-color: transparent; }");
ui->pushButton->setStyleSheet("QPushButton { background-color: transparent; }");
// 设置QLineEdit的背景为透明
ui->plainTextMsg->setStyleSheet("QLineEdit { background-color: transparent; }");
}
Dialog::~Dialog()
{
//关闭窗口会调用析构函数
//便于关闭窗口也是断开
disconnect(client,SIGNAL(disconnected()),this,SLOT(dissConnetSlot()));
if(client->isOpen())
client->close();
delete ui;
}
//显示信息再框里
void Dialog::showMesg(QString msg)
{
QString time=QDateTime::currentDateTime().toString("yy:MM:dd hh:mm:ss");
ui->textBrowser->append(time);
ui->textBrowser->append(msg);
}
/**
* @brief Dialog::disconnectedSlot 断开连接
*/
void Dialog::disconnectedSlot()
{
QString name=ui->lineEditName->text();
//拼接信息
QString text=QString::number(port).prepend(':').prepend(ip).prepend("已下线").prepend(name);
//通知
showMesg(text);
qDebug()<<text;
QMessageBox::information(this,"警告","您已下线");
this->close();
delete ui;
disconnect(client,SIGNAL(disconnected()),this,SLOT(disconnectedSlot()));
// //恢复昵称
// ui->lineEditName->setText(true);
QMessageBox::information(this,"提示","连接已断开");
qDebug()<<"已断开连接";
}
void Dialog::netSuccessSlot()
{
qDebug()<<"网络已经连接";
}
void Dialog::errorSlot()
{
QMessageBox::warning(this,"警告","未连接到网络");
this->close();
}
void Dialog::historySlot()
{
//获取用户名
QString name=ui->lineEditName->text();
if(name=="")
{
QMessageBox::information(this,"提示","请输入用户名");
return;
}
//开启查询聊天记录按钮
ui->pushButtonChat->setEnabled(true);
//清空文本框
ui->plainTextMsg->clear();
QString mssgg="历史记录";
//创建文本流对象
QTextStream output(client);
//发出数据 昵称和数据
output<<name.append(":")<<mssgg;
}
//连接的槽函数
void Dialog::connectSlot()
{
qDebug()<<"正在连接";
//向服务器发起连接请求
qDebug()<<"这是ip"<<ip<<port;
}
///发送消息
void Dialog::btnSendSlot()
{
///获取信息
QString name=ui->lineEditName->text();
QString msg=ui->plainTextMsg->toPlainText();
if(name=="")
{
QMessageBox::information(this,"提示","请输入用户名");
return;
}
if(msg=="")
{
QMessageBox::information(this,"提示","请输入要发送的信息!");
return ;
}
//限制发送内容的大小
if(msg.size()>=200)
{
//只保留200个字符
msg=msg.left(200);
}
//关闭昵称按钮
ui->lineEditName->setEnabled(false);
//创建文本流对象
QTextStream output(client);
//发出数据 昵称和数据
output<<name.append(":")<<msg;
//清空输入框
ui->plainTextMsg->clear();
}
//读取信息
void Dialog::readReSLot()
{
// //将socket添加到列表中
// clientList.append(client);
QTextStream input(client);
QString text=input.readAll();
showMesg(text);
}
服务器
.h文件
#ifndef DIALOG_H
#define DIALOG_H
#include <QDialog>
#include<QDebug>
#include<QPixmap>
#include<QPainter>//画家对象
#include<QTcpServer>//服务器对象
#include<QList>
#include<QTextStream>//文本流
#include<QDateTime>
#include<QTcpSocket>
#include<QSqlDatabase>//数据库连接对象
#include<QSqlError>//数据库错误
#include<QSqlQuery>//数据库操作类
#include<QStringList>
namespace Ui {
class Dialog;
}
class Dialog : public QDialog
{
Q_OBJECT
public:
explicit Dialog(QWidget *parent = 0);
~Dialog();
protected:
//就得用这个名字,函数发生倾斜就对了
void paintEvent(QPaintEvent *event);
private:
Ui::Dialog *ui;
//创建服务器对象
QTcpServer *server;
void printBrowser(QString);//在滚动条显示
//保存所有用户的连接,实现多用户
QList<QTcpSocket *>clientlist;
//保存新连接
QTcpSocket *socket;
QSqlDatabase db;///数据库连接对象,栈内存
void connect2Db();///连接到数据库
void creatTable();//建表
int number=0;//新连接人数
QString record2;//记录历史记录
void pepole(int );//在线人数
int i;//记录发送消息的人,便于历史记录的查询
void history();//查询历史记录
void sendHistory(QString);//发送历史记录
void insert(QString msg);//插入数据
private slots:
void newConetSlot();//连接
void disConSlot();//断开连接检测
void readyReadSlot();//接收消息的槽函数
};
#endif // DIALOG_H
.cpp文件
#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);
//开启监听
bool result=server->listen(QHostAddress::Any,8887);
if(result)
{
printBrowser("服务器监听成功!端口号为8887");
//建立新连接来的信号槽
//自带信号
connect(server,SIGNAL(newConnection()),this,SLOT(newConetSlot()));
}
else
printBrowser("服务器监听失败!请重新换端口号,谢谢!!");
//连接数据库
connect2Db();
}
Dialog::~Dialog()
{
// 如果正在监听就关闭
if(server->isListening())
server->close();
delete ui;
}
//创建背景
void Dialog::paintEvent(QPaintEvent *event)
{
//背景透明
ui->textBrowser->setStyleSheet("QTextBrowser { background-color: transparent; }");
// qDebug()<<event;
///创建画家对象
/// 参数为哪儿画,继承QPaintDevice的类对象才能被绘制
QPainter painter(this);
//创建一个要画的图片对象
QPixmap pic(":/new/prefix1/img/2.jpg");
//开始绘制
//参数1/2:绘制的坐标;
//参数3&4:绘制的宽高;
//参数5:绘制的内容;
painter.drawPixmap(0,0,this->width(),this->height(),pic);
}
//连接数据库
void Dialog::connect2Db()
{
//获取数据库连接对像 改变这个对像会出错
db=QSqlDatabase::addDatabase("QSQLITE");
//设置数据库文件名称 .db .db3 pasture牧场
db.setDatabaseName("chat_xx.db");
///连接到数据库
if(db.open())
{
qDebug()<<"数据库连接成功";
//建表
creatTable();
}
else
{
//获取错误信息,展示·给用户
QSqlError err=db.lastError();
//转为text文本 便于显示
QString text=err.text();
//往前追加错误信息
text.prepend("连接错误! ");
//输出错误信息
qDebug()<<"建表失败"<<text;
}
}
//建表
void Dialog::creatTable()
{
// 字符串内部换行使用'\'
QString sql = "CREATE TABLE server(\
time TEXT ,\
name TEXT,\
message TEXT\
);\
";
//创建一个数据库操作类对象
QSqlQuery sq;
///执行SQL语句
if(sq.exec(sql))
{
qDebug()<<"建表成功";
}
else
{
//输出错误信息
QString text=sq.lastError().text();
qDebug()<<"建表失败 "<<text;
}
}
//在线人数
void Dialog::pepole(int ii)
{
QString str = QString::number(ii);
ui->textBrowserPeople->append(str);
}
//插入数据
void Dialog::insert(QString msg)
{
qDebug()<<"我正在插入数据";
qDebug()<<msg;
QStringList list=msg.split(':');
QString time=list[0];
QString name=list[1];
QString message=list[2];
qDebug()<<"分割后";
QString sql = "INSERT INTO server VALUES(:time,:name,:message);";
QSqlQuery sq;
// 预处理
sq.prepare(sql);
// 参数绑定(Oracle风格可以乱序)
sq.bindValue(":time",time);
sq.bindValue(":name",name);
sq.bindValue(":message",message);
// 执行拼接后的预处理语句
if(sq.exec())
qDebug() << "成功插入历史表";
else
{
// 获得错误信息
QString text = sq.lastError().text().prepend("插入失败!");
qDebug()<<"插入失败"<<text;
}
}
//信息显示
void Dialog::printBrowser(QString msg)
{
// //获得系统的日期和时间
// QString time=QDateTime::currentDateTime().toString("yyyy-MM-dd hh:mm:ss");
// ui->textBrowser->append(time);
ui->textBrowser->append(msg);
}
//新连接
void Dialog::newConetSlot()
{
ui->textBrowserPeople->clear();
number++;
// 现在str包含"123"
pepole(number);//在线人数
//接收新连接
socket=server->nextPendingConnection();
//断开连接的信号槽
connect(socket,SIGNAL(disconnected()),this,SLOT(disConSlot()));
//接收信息的信号槽
connect(socket,SIGNAL(readyRead()),this,SLOT(readyReadSlot()));
//存信息 列表
clientlist.append(socket);
//获取客户端信息 顺带转化为QString
QString ip=socket->peerAddress().toString();
quint16 port=socket->peerPort();
//拼接信息
QString text=QString::number(port).prepend(':').prepend(ip).prepend("新上线!");
\
//通知给框
printBrowser(text);
qDebug()<<text;
QTextStream input(socket);
QString tex1t = "你已经成功连接服务器";
tex1t=input.readAll();
}
//断开连接
void Dialog::disConSlot()
{
ui->textBrowserPeople->clear();
number--;
pepole(number );//在线人数
//获取客户端信息 顺带转化为QString
QString ip=socket->peerAddress().toString();
quint16 port=socket->peerPort();
//拼接信息
QString text=QString::number(port).prepend(':').prepend(ip).prepend("连接已断开 ");
//通知
printBrowser(text);
qDebug()<<text;
}
//查询历史记录
void Dialog::history()
{
QString sql = "SELECT * FROM server";
QSqlQuery sq;
if(sq.exec(sql))
{
QString record2;
// 判断有无数据
while(sq.next())
{
QString time = sq.value(0).toString(); // 使用索引取出
QString name = sq.value(1).toString();
QString message = sq.value(2).toString();
// 拼接
QString record1 = time.append(" ")+name.append(" ")+message;
//换行
record2.append(record1).append("\n");
}
record2.append("历史记录已查询完毕!");
//只发给能需要的人
QTextStream output(clientlist.at(i));
output<<record2;
qDebug() << record2;
}else
{
// 获得错误信息
QString text = sq.lastError().text().prepend("查询失败!");
qDebug()<<text;
}
}
//读数据发数据
void Dialog::readyReadSlot()
{
qDebug()<<"我正在进入";
for( i=0;i<clientlist.size();i++)
{
if(clientlist.at(i)->isReadable()&&clientlist.at(i)->bytesAvailable()>0)
{
qDebug()<<"我正在读取";
// pepole(i);
//创建文本流对象 栈对象
QTextStream input(clientlist.at(i));
//读取所有数据
QString text = input.readAll();
qDebug()<<"我读取到的消息为"<<text;
//数据分割
QStringList list=text.split(':');
QString name=list[0];
QString message=list[1];
qDebug()<<"我读取到的消息为message"<<message;
if(message=="历史记录")
{
history();
}
else
{
//获得系统的日期和时间
QString time=QDateTime::currentDateTime().toString("yyyy-MM-dd hh-mm-ss ");
QString timee=time.append(":")+text;
qDebug()<<timee;
//显示在文本框
printBrowser(timee);
insert(timee);
qDebug()<<"这是数据"<<text;
// 发送数据给所有用户 遍历每一个用户
for(int j=0;j<clientlist.size();j++)
{
qDebug()<<"我正在进入";
//发送消息 只发一次
QTextStream output(clientlist.at(j));
output<<text;
qDebug()<<"发送的消息为"<<text;
}
}
}
}
}