QT--聊天室

一、设计要求

用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);
                     }
                  }



            }
        }



}

四、项目结果

基于Qt多线程的聊天室是一种使用Qt框架实现的多线程网络通信应用程序。Qt是一个跨平台的C++应用程序开发框架,其多线程机制可用于实现并发网络通信。聊天室是一种允许多个用户在互联网上进行实时文本交流的在线平台。 基于Qt多线程的聊天室应用程序可以通过使用Qt的多线程类和网络通信模块来实现。首先,需要创建一个服务器程序,该程序使用QtQtNetwork模块来监听用户的连接请求。当一个用户连接到服务器时,服务器会为其分配一个独立的线程来处理该用户的请求。这样,每个用户都可以在自己的线程中进行聊天,并与其他用户实时地进行消息传递。 在服务器端的实现中,需要使用QtQThread类来创建多个线程,并使用QTcpServer类来监听用户的连接请求。每个用户连接时,服务器会创建一个新的线程,并将该线程的socket连接用于与用户进行通信。 在客户端的实现中,需要使用QtQTcpSocket类来连接到服务器,并在一个独立的线程中进行读写操作。客户端可以通过使用Qt提供的信号和槽机制来与服务器进行消息的发送和接收。 总结来说,基于Qt多线程的聊天室是一种通过使用Qt框架的多线程和网络通信模块来实现的聊天应用程序。其优势是能够支持多个用户同时进行实时的文本交流,提高了并发处理能力,同时也提高了用户体验和程序的稳定性。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值