QT实现聊天室

功能

● 支持多客户端群聊功能

● 支持聊天记录保存功能,可以进行查询

● 美化样式

● 打包

● 人脸检测

● 用户登录

● 头像

客户端代码

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;

                }
            }
        }
    }
}




界面实现,实现效果

  • 7
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
好的,以下是用QT实现聊天室的用户可以邀请其他用户加入该聊天室代码示例: 1. 在客户端UI界面添加邀请按钮: ```cpp QPushButton *inviteButton = new QPushButton(tr("邀请")); connect(inviteButton, &QPushButton::clicked, this, &ChatClient::inviteUser); ``` 2. 在客户端中实现inviteUser()槽函数: ```cpp void ChatClient::inviteUser() { bool ok; QString userName = QInputDialog::getText(this, tr("邀请用户"), tr("请输入被邀请人的用户名:"), QLineEdit::Normal, "", &ok); if (ok && !userName.isEmpty()) { // 将被邀请人的用户名打包成邀请消息 QString inviteMsg = QString("invite|%1|%2").arg(m_userName).arg(userName); // 发送邀请消息给服务器 m_socket->write(inviteMsg.toUtf8()); } } ``` 3. 在服务器中实现处理邀请消息的代码: ```cpp void ChatServer::processMessage(QString message, QTcpSocket *clientSocket) { // 解析收到的消息 QStringList msgList = message.split("|"); QString msgType = msgList.at(0); QString sender = msgList.at(1); QString receiver = msgList.at(2); if (msgType == "invite") { // 如果是邀请消息,将消息转发给被邀请人 QString inviteMsg = QString("invite|%1|%2").arg(sender).arg(receiver); sendToClient(inviteMsg, receiver); } // ... } ``` 4. 在被邀请人的客户端中实现处理邀请消息的代码: ```cpp void ChatClient::processInvite(QString sender, QString receiver) { // 弹出对话框,让用户选择是否接受邀请 QMessageBox::StandardButton reply; reply = QMessageBox::question(this, tr("邀请"), tr("%1邀请你加入聊天室,是否接受?").arg(sender), QMessageBox::Yes|QMessageBox::No); if (reply == QMessageBox::Yes) { // 如果接受邀请,连接到服务器并加入聊天室 connectToServer(); joinChatRoom(); } else { // 如果拒绝邀请,发送一个提示消息给邀请人 QString refuseMsg = QString("refuse|%1|%2").arg(receiver).arg(sender); m_socket->write(refuseMsg.toUtf8()); } } ``` 5. 在服务器中实现处理拒绝邀请消息的代码: ```cpp void ChatServer::processMessage(QString message, QTcpSocket *clientSocket) { // 解析收到的消息 QStringList msgList = message.split("|"); QString msgType = msgList.at(0); QString sender = msgList.at(1); QString receiver = msgList.at(2); if (msgType == "refuse") { // 如果是拒绝邀请消息,发送一个提示消息给邀请人 QString tipMsg = QString("%1拒绝了你的邀请!").arg(receiver); sendToClient(tipMsg, sender); } // ... } ``` 以上是一个简单的示例代码,可以根据你的具体需求进行调整和优化。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值