当前位置: 首页 > article >正文

Qt聊天室项目

目录

项目要求

项目背景

技术分析

架构设计

 服务器架构

 模块划分

 模块之间的交互

 客户端架构

 模块划分

模块之间交互

 项目展示

项目实现

服务器

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 += widgets

TARGET = server
TEMPLATE = app


SOURCES += main.cpp\
        dialog.cpp

HEADERS  += dialog.h

FORMS    += dialog.ui

RESOURCES += \
    res.qrc

DISTFILES += \
    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_OBJECT

public:
    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()));
    }
    else
        printMsg("监听开启失败!");
    //连接数据库
    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(":");

            //注册信息,服务器接收通过“:”拆分长度为2
            if(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);
                    }
                }

            }
            //服务器接收通过“:”拆分长度为3
            if(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("登录失败");
                    }
                }
            }

            //收到聊天信息,服务器接收通过“:”拆分长度为4
            if(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);
                }
            }
            //客户端接收通过“:”拆分长度为1
            if(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);
    // 预处理的SQL
    QString 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);
    // 预处理的SQL
    QString 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.rc

greaterThan(QT_MAJOR_VERSION, 4): QT += widgets

TARGET = client
TEMPLATE = app


SOURCES += main.cpp\
        dialog.cpp

HEADERS  += dialog.h

FORMS    += dialog.ui

RESOURCES += \
    res.qrc

DISTFILES += \
    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_OBJECT

public:
    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"; //服务器接收通过“:”拆分长度为4
    QString 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=989c862553a9fc170dee4fdcac7a0592icon-default.png?t=O83Ahttp://【Qt聊天室】 https://www.bilibili.com/video/BV1uW1MYbEZz/?share_source=copy_web&vd_source=989c862553a9fc170dee4fdcac7a0592

————源码已上传


http://www.kler.cn/a/380028.html

相关文章:

  • 嵌入式硬件工程师的职业发展规划
  • 手动搭建 LNMP 环境(Ubuntu)
  • 2024江苏省网络建设与运维省赛linux解析答案(整合)
  • VSCode 1.82之后的vscode server离线安装
  • leetcode-88-合并两个有序数组
  • 【学习】软件测试中的过程管理为何如此重要
  • 【系统架构设计师(第2版)】目录
  • 深入解析 Linux initramfs:从基础到高级应用
  • python机器人Agent编程——实现一个机器人DH参数自动生成Agent(上)
  • 基于STM32设计的物联网火灾感知系统(259)
  • 数字IC中Verilog编码注意事项
  • 数据安全秘籍:500强企业的经典传输案例大揭秘
  • [QUIC] 版本协商
  • 重构代码之重复的观察数据
  • C语言用GNU源码编译建构系统工具(GNU BUILD SYSTEM)编译创建动态库
  • 微服务系列二:跨微服务请求优化,注册中心+OpenFeign
  • 输电线路绝缘子缺陷分割系统:轻松训练模式
  • 【matlab版】如何估算波形信号的幅值、频率与相位
  • Docker BUG排查
  • Docker 部署 Java 项目实践
  • Windows下FFmpeg集成metaRTC实现webrtc推拉流的例子
  • 深度学习基础(2024-11-02更新到图像尺寸变换 与 裁剪)
  • js实现漂亮的注册页面(js动态注册页面)
  • 使用 Nginx 部署 Python 项目
  • 【系统设计】高效的分布式系统:使用 Spring Boot 和 Kafka 实现 Saga 模式
  • 【STM32】STM32G431RBT6单片机的几种烧录方式