QQ聊天室--C++基础项目--QT+Socket网络编程

发布于:2024-12-18 ⋅ 阅读:(196) ⋅ 点赞:(0)

目录

一、项目概述

二、项目成果

1、QQ基础界面展示:

2、群聊界面展示:

3、聊天功能展示

三、项目代码

1、登录头文件(denglu.h)

2、登录源文件(denglu.cpp)

3、聊天界面头文件(widget.h)

4、聊天界面源文件(widget.cpp)

四、项目优化


一、项目概述

        本项目的目标是创建一个QQ聊天室应用,旨在作为学习基础QT语法和网络编程中Socket编程的入门练习。我们利用QT框架来设计并实现QQ的基础用户界面以及群聊窗口,同时,通过Socket编程技术,实现了用户之间的消息群发功能。

二、项目成果

1、QQ基础界面展示:

        QQ基础界面如下图所示,页面中展示各个用户,通过点击用户,可以进入群聊界面。

2、群聊界面展示:

       点击用户,即可进入群聊,群聊界面展示用户上线、下线、在线人数等信息。消息输入框中能够选择字体、加粗、颜色等功能。

3、聊天功能展示

        用户在群聊中发送信息,可以显示用户名称和时间。

三、项目代码

        在文章置顶中有zip文件

1、登录头文件(denglu.h)

#ifndef DENGLU_H
#define DENGLU_H

#include <QWidget>

namespace Ui {
class denglu;
}

class denglu : public QWidget
{
    Q_OBJECT

public:
    explicit denglu(QWidget *parent = nullptr);
    ~denglu();

private:
    Ui::denglu *ui;

    QVector<bool> IsShow;
};

#endif // DENGLU_H

2、登录源文件(denglu.cpp)

        用于实现头文件中的函数,主要是添加用户和链接群聊界面。

#include "denglu.h"
#include "ui_denglu.h"
#include<QIcon>
#include<QToolButton>
#include<QMessageBox>
#include<widget.h>

denglu::denglu(QWidget *parent)
    : QWidget(parent)
    , ui(new Ui::denglu)
{
    ui->setupUi(this);
    //设置图标
    //路径:“:+前缀+路径”
    this->setWindowIcon(QIcon(":/images/QQ.jpg"));
    //设置名称
    this->setWindowTitle("QQ 2024");

    QList<QString> nameList;
    nameList << "绿巨人" << "钢铁侠" << "美国队长";
    QStringList iconNameList;
    iconNameList << "hulk01" << "gang01" << "mei01";

    QVector<QToolButton *> vectorbtn;

    for(int i = 0; i < 3; i++){
        QToolButton *btn = new QToolButton(this);

        // 加载图片
        btn->setIcon(QIcon(QString(":/images/%1.jpg").arg(iconNameList[i])));
        // 设置图片大小
        btn->setIconSize(QSize(100, 100));
        // 设置网名
        btn->setText(QString("%1").arg(nameList[i]));
        // 设置为透明
        btn->setAutoRaise(true);
        // 设置显示格式
        btn->setToolButtonStyle(Qt::ToolButtonTextBesideIcon);
        // 放到vlayout布局
        ui->vlayout->addWidget(btn);

        vectorbtn.push_back(btn);

        IsShow.push_back(false);
    }

    // 将按钮进行连接聊天框
    for(int i = 0; i < 3; i++){
        connect(vectorbtn[i], &QToolButton::clicked, [=](){

            if(IsShow[i]){
                QMessageBox::warning(this, "警告", "该聊天框已被打开!");
                return;
            }

            IsShow[i] = true;
            Widget *widger = new Widget(nullptr, vectorbtn[i]->text());
            widger->setWindowIcon(vectorbtn[i]->icon());
            widger->setWindowTitle(vectorbtn[i]->text());
            widger->show();

            // 关闭聊天框时,将IsShow变为False
            connect(widger, &Widget::closeWidget, this, [=]{
                IsShow[i] = false;
            });
        });
    }
}

denglu::~denglu()
{
    delete ui;
}

3、聊天界面头文件(widget.h)

        用于定义聊天界面功能的函数。

#ifndef WIDGET_H
#define WIDGET_H

#include <QWidget>
#include <QUdpSocket>

QT_BEGIN_NAMESPACE
namespace Ui {
class Widget;
}
QT_END_NAMESPACE

class Widget : public QWidget
{
    Q_OBJECT

public:

    explicit Widget(QWidget *parent = nullptr, QString name = "");

    enum Msgtype{Msg, UserEnter, UserLeft};
    void sndMsg(Msgtype type); //广播udp信息
    QString getName(); //获取名字
    QString getMsg(); //获取聊天信息
    void userEnter(QString username); //处理用户进入
    void userLeft(QString username, QString time); //处理用户离开
    void ReceiveMessage(); // 接受UDP信息

    //重写关闭事件
    void closeEvent(QCloseEvent *);
    ~Widget();

signals:
    void closeWidget();

private:
    Ui::Widget *ui;
    QString myname;

    quint16 port; // 端口
    QUdpSocket *udpSocket; // UDP套接字

};
#endif // WIDGET_H

4、聊天界面源文件(widget.cpp)

        主要部分,用于实现聊天功能。

#include "widget.h"
#include "ui_widget.h"
#include<QMessageBox>
#include<QDateTime>
#include<QColorDialog>
#include<QFileDialog>

Widget::Widget(QWidget *parent, QString name)
    : QWidget(parent)
    , ui(new Ui::Widget)
{
    ui->setupUi(this);
    myname = name;

    this->port = 9999;
    this->udpSocket = new QUdpSocket(this);

    udpSocket->bind(port, QUdpSocket::ShareAddress |QUdpSocket::ReuseAddressHint);

    //监听信号
    connect(udpSocket, &QUdpSocket::readyRead, this, &Widget::ReceiveMessage);

    //连接发送按钮
    connect(ui->sendTBtn, &QPushButton::clicked, [=](){
        sndMsg(Msg);
    });

    //新用户进入
    sndMsg(UserEnter);

    //连接退出按钮
    connect(ui->exitTBtn, &QPushButton::clicked, [=]{
        this->close();
    });

    //连接字体
    connect(ui->fontCbx, &QFontComboBox::currentFontChanged, [=](const QFont &font){
        ui->msgTxtEdit->setFont(font);
        ui->msgTxtEdit->setFocus();
    });

    //连接字体大小
    void (QComboBox:: *sizebtn)(const QString &text) = &QComboBox::currentTextChanged;
    connect(ui->sizeCbx, sizebtn, [=](const QString &text){
        ui->msgTxtEdit->setFontPointSize(text.toDouble());
        ui->msgTxtEdit->setFocus();
    });

    //字体加粗
    connect(ui->boldTBtn, &QToolButton::clicked, this, [=](bool checked){
        if(checked){
            ui->msgTxtEdit->setFontWeight(QFont::Bold);
        }
        else{
            ui->msgTxtEdit->setFontWeight(QFont::Normal);
        }
    });

    //字体倾斜
    connect(ui->italicTbtn, &QToolButton::clicked, this, [=](bool checked){
        ui->msgTxtEdit->setFontItalic(checked);
        ui->msgTxtEdit->setFocus();
    });

    //下划线
    connect(ui->underlineTBtn, &QToolButton::clicked, this, [=](bool checked){
        ui->msgTxtEdit->setFontUnderline(checked);
        ui->msgTxtEdit->setFocus();
    });

    //设置文本颜色
    connect(ui->colorTBtn, &QToolButton::clicked, this, [=](){
        QColor color = QColorDialog::getColor(color, this);
        ui->msgTxtEdit->setTextColor(color);
    });

    //清空聊天记录
    connect(ui->clearTBtn, &QToolButton::clicked, [=](){
        ui->msgBrowser->clear();
    });

    //保存聊天记录
    connect(ui->saveTBtn, &QToolButton::clicked, [=](){
        if(ui->msgBrowser->document()->isEmpty()){
            QMessageBox::warning(this, "警告", "保存的信息不能为空!");
        }
        else{
            QString filename = QFileDialog::getSaveFileName(this, "保存聊天记录", "聊天记录", "(*.txt)");
            if(!filename.isEmpty()){
                //保存名称不能为空,再进行保存
                QFile file(filename);
                file.open(QIODevice::WriteOnly | QFile::Text);
                QTextStream stream(&file);
                stream<<ui->msgBrowser->toPlainText();
                file.close();
            }
        }
    });

}

//广播信号
void Widget::sndMsg(Msgtype type)
{
    QByteArray array;
    QDataStream stream(&array, QIODevice::WriteOnly);

    stream<<type<<this->getName();

    switch(type){
    case Msg:
        if(ui->msgTxtEdit->toPlainText()==""){
            QMessageBox::warning(this, "警告", "发送的内容不能为空!");
            return;
        }
        stream<<this->getMsg();
        break;
    case UserEnter:
        break;
    case UserLeft:
        break;
    }

    // 书写报文
    udpSocket->writeDatagram(array.data(), array.size(), QHostAddress::Broadcast, this->port);

}



QString Widget::getName()
{
    return this->myname;
}

QString Widget::getMsg()
{
    QString msg = ui->msgTxtEdit->toHtml();
    ui->msgTxtEdit->clear();
    ui->msgTxtEdit->setFocus();
    return msg;
}

void Widget::userEnter(QString username)
{
    bool isEmpty = ui->usrTblWidget->findItems(username, Qt::MatchExactly).isEmpty();

    if(isEmpty){
        QTableWidgetItem *user = new QTableWidgetItem(username);
        ui->usrTblWidget->insertRow(0);
        ui->usrTblWidget->setItem(0,0,user);
        ui->msgBrowser->setTextColor(Qt::gray);
        ui->msgBrowser->append(username+"用户已上线");
        ui->userNumLbl->setText(QString("在线人数:%1人").arg(ui->usrTblWidget->rowCount()));
        sndMsg(UserEnter);
    }
}

void Widget::userLeft(QString username, QString time)
{
    bool isEmpty = ui->usrTblWidget->findItems(username, Qt::MatchExactly).isEmpty();

    if(!isEmpty){
        //寻找行
        int row = ui->usrTblWidget->findItems(username, Qt::MatchExactly).first()->row();
        //移除行
        ui->usrTblWidget->removeRow(row);

        //追加信息
        ui->msgBrowser->setTextColor(Qt::gray);
        ui->msgBrowser->append(username+"用户于"+time+"下线");
        ui->userNumLbl->setText(QString("在线人数:%1").arg(ui->usrTblWidget->rowCount()));
    }
}

void Widget::ReceiveMessage()
{
    qint64 size = udpSocket->pendingDatagramSize();
    int mysize = static_cast<int>(size);
    QByteArray array = QByteArray(mysize, 0);
    udpSocket->readDatagram(array.data(), size);
    QDataStream stream(&array, QIODevice::ReadOnly);

    int msgtype;
    stream>>msgtype;

    QString name,msg;
    QString time = QDateTime::currentDateTime().toString("yyyy-MM-dd hh:mm:ss");

    switch(msgtype){
    case Msg:
        stream>>name>>msg;

        //增加聊天记录
        ui->msgBrowser->setTextColor(Qt::blue);
        ui->msgBrowser->setCurrentFont(QFont("Times New Roman",12));
        ui->msgBrowser->append("["+name+"]"+time);
        ui->msgBrowser->append(msg);
        break;
    case UserEnter:
        stream>>name;
        userEnter(name);
        break;
    case UserLeft:
        stream>>name;
        userLeft(name, time);
        break;
    }
}

Widget::~Widget()
{
    delete ui;
}

void Widget::closeEvent(QCloseEvent *)
{
    emit this->closeWidget();

    sndMsg(UserLeft);

    udpSocket->close();
    udpSocket->destroyed();
}

四、项目优化

        1、实现注册登录功能:与数据库进行连接。

        2、界面美化:界面简单,未考虑美化问题。


网站公告

今日签到

点亮在社区的每一天
去签到