基于Qt的仿QQ聊天系统设计

设计思路

系统需要包含以下核心功能:

  • 用户登录界面
  • 好友列表展示
  • 一对一聊天功能
  • 消息发送与接收
  • 消息历史记录

实现方案

核心类设计

  1. LoginWindow:登录界面
  2. MainWindow:主界面(包含好友列表和聊天区域)
  3. ChatDialog:聊天对话框
  4. ClientManager:客户端管理类(处理网络通信)
  5. Message:消息数据结构

界面设计预览

成功登录 登录界面 主界面 好友列表 聊天区域 消息显示区 消息输入区 发送按钮

代码实现

1. 登录界面 (LoginWindow)

cpp 复制代码
// LoginWindow.h
#include <QWidget>
#include <QLabel>
#include <QLineEdit>
#include <QPushButton>
#include <QVBoxLayout>
#include <QHBoxLayout>

class LoginWindow : public QWidget {
    Q_OBJECT
public:
    LoginWindow(QWidget *parent = nullptr);
    
signals:
    void loginRequested(const QString &username, const QString &password);
    
private slots:
    void onLoginClicked();
    
private:
    QLineEdit *usernameEdit;
    QLineEdit *passwordEdit;
    QPushButton *loginButton;
};
cpp 复制代码
// LoginWindow.cpp
#include "LoginWindow.h"

LoginWindow::LoginWindow(QWidget *parent) : QWidget(parent) {
    setWindowTitle("QQ聊天系统 - 登录");
    setFixedSize(300, 200);
    
    QLabel *titleLabel = new QLabel("欢迎使用QQ聊天系统", this);
    titleLabel->setAlignment(Qt::AlignCenter);
    
    usernameEdit = new QLineEdit(this);
    usernameEdit->setPlaceholderText("用户名");
    
    passwordEdit = new QLineEdit(this);
    passwordEdit->setPlaceholderText("密码");
    passwordEdit->setEchoMode(QLineEdit::Password);
    
    loginButton = new QPushButton("登录", this);
    
    QVBoxLayout *layout = new QVBoxLayout(this);
    layout->addWidget(titleLabel);
    layout->addWidget(usernameEdit);
    layout->addWidget(passwordEdit);
    layout->addWidget(loginButton);
    
    connect(loginButton, &QPushButton::clicked, this, &LoginWindow::onLoginClicked);
}

void LoginWindow::onLoginClicked() {
    QString username = usernameEdit->text().trimmed();
    QString password = passwordEdit->text().trimmed();
    
    if (username.isEmpty() || password.isEmpty()) {
        QMessageBox::warning(this, "登录失败", "用户名和密码不能为空");
        return;
    }
    
    emit loginRequested(username, password);
}

2. 主界面 (MainWindow)

cpp 复制代码
// MainWindow.h
#include <QMainWindow>
#include <QSplitter>
#include <QListWidget>
#include <QStackedWidget>
#include "ChatDialog.h"

class MainWindow : public QMainWindow {
    Q_OBJECT
public:
    MainWindow(const QString &username, QWidget *parent = nullptr);
    
public slots:
    void showChatWindow(const QString &friendName);
    void addFriend(const QString &friendName);
    void receiveMessage(const QString &from, const QString &message);
    
private:
    void setupUI();
    void createFriendsList();
    
    QString currentUser;
    QListWidget *friendsList;
    QStackedWidget *chatStack;
    QMap<QString, ChatDialog*> chatWindows;
};
cpp 复制代码
// MainWindow.cpp
#include "MainWindow.h"

MainWindow::MainWindow(const QString &username, QWidget *parent)
    : QMainWindow(parent), currentUser(username) {
    setWindowTitle("QQ聊天系统 - " + username);
    setMinimumSize(800, 600);
    
    setupUI();
    createFriendsList();
}

void MainWindow::setupUI() {
    QSplitter *splitter = new QSplitter(this);
    
    friendsList = new QListWidget(splitter);
    friendsList->setFixedWidth(200);
    
    chatStack = new QStackedWidget(splitter);
    
    setCentralWidget(splitter);
    
    connect(friendsList, &QListWidget::itemDoubleClicked, [this](QListWidgetItem *item) {
        showChatWindow(item->text());
    });
}

void MainWindow::createFriendsList() {
    // 模拟好友列表
    QStringList friends = {"张三", "李四", "王五", "赵六"};
    for (const QString &friendName : friends) {
        addFriend(friendName);
    }
}

void MainWindow::addFriend(const QString &friendName) {
    QListWidgetItem *item = new QListWidgetItem(friendName, friendsList);
    item->setIcon(QIcon(":/icons/user.png"));
}

void MainWindow::showChatWindow(const QString &friendName) {
    if (!chatWindows.contains(friendName)) {
        ChatDialog *chatDialog = new ChatDialog(currentUser, friendName, this);
        chatStack->addWidget(chatDialog);
        chatWindows.insert(friendName, chatDialog);
    }
    
    ChatDialog *chat = chatWindows.value(friendName);
    chatStack->setCurrentWidget(chat);
    chat->activateWindow();
}

void MainWindow::receiveMessage(const QString &from, const QString &message) {
    if (!chatWindows.contains(from)) {
        addFriend(from);
        showChatWindow(from);
    }
    
    ChatDialog *chat = chatWindows.value(from);
    chat->receiveMessage(message);
}

3. 聊天对话框 (ChatDialog)

cpp 复制代码
// ChatDialog.h
#include <QWidget>
#include <QTextEdit>
#include <QLineEdit>
#include <QPushButton>
#include <QVBoxLayout>
#include <QHBoxLayout>

class ChatDialog : public QWidget {
    Q_OBJECT
public:
    ChatDialog(const QString &currentUser, const QString &friendName, QWidget *parent = nullptr);
    
public slots:
    void receiveMessage(const QString &message);
    
signals:
    void sendMessage(const QString &to, const QString &message);
    
private slots:
    void onSendClicked();
    
private:
    QString currentUser;
    QString friendName;
    QTextEdit *messageDisplay;
    QLineEdit *messageInput;
    QPushButton *sendButton;
};
cpp 复制代码
// ChatDialog.cpp
#include "ChatDialog.h"
#include <QDateTime>
#include <QScrollBar>

ChatDialog::ChatDialog(const QString &currentUser, const QString &friendName, QWidget *parent)
    : QWidget(parent), currentUser(currentUser), friendName(friendName) {
    setWindowTitle("与 " + friendName + " 聊天");
    
    QVBoxLayout *layout = new QVBoxLayout(this);
    
    messageDisplay = new QTextEdit(this);
    messageDisplay->setReadOnly(true);
    layout->addWidget(messageDisplay);
    
    QHBoxLayout *inputLayout = new QHBoxLayout();
    messageInput = new QLineEdit(this);
    sendButton = new QPushButton("发送", this);
    
    inputLayout->addWidget(messageInput, 1);
    inputLayout->addWidget(sendButton);
    
    layout->addLayout(inputLayout);
    
    connect(sendButton, &QPushButton::clicked, this, &ChatDialog::onSendClicked);
    connect(messageInput, &QLineEdit::returnPressed, this, &ChatDialog::onSendClicked);
}

void ChatDialog::receiveMessage(const QString &message) {
    QString time = QDateTime::currentDateTime().toString("hh:mm:ss");
    QString formattedMsg = QString("<div style='margin:5px;'>"
                                  "<b>%1</b> [%2]:<br>%3</div>")
                          .arg(friendName, time, message);
    
    messageDisplay->append(formattedMsg);
    
    // 滚动到底部
    QScrollBar *scrollbar = messageDisplay->verticalScrollBar();
    scrollbar->setValue(scrollbar->maximum());
}

void ChatDialog::onSendClicked() {
    QString message = messageInput->text().trimmed();
    if (message.isEmpty()) return;
    
    QString time = QDateTime::currentDateTime().toString("hh:mm:ss");
    QString formattedMsg = QString("<div style='margin:5px; text-align:right; color:blue;'>"
                                  "<b>我</b> [%1]:<br>%2</div>")
                          .arg(time, message);
    
    messageDisplay->append(formattedMsg);
    messageInput->clear();
    
    emit sendMessage(friendName, message);
}

4. 客户端管理 (ClientManager)

cpp 复制代码
// ClientManager.h
#include <QObject>
#include <QTcpSocket>
#include <QHostAddress>

class ClientManager : public QObject {
    Q_OBJECT
public:
    ClientManager(QObject *parent = nullptr);
    
    void connectToServer(const QString &host, quint16 port);
    void login(const QString &username, const QString &password);
    void sendMessage(const QString &to, const QString &message);
    
signals:
    void connected();
    void loginSuccess();
    void loginFailed(const QString &reason);
    void messageReceived(const QString &from, const QString &message);
    void errorOccurred(const QString &error);
    
private slots:
    void onConnected();
    void onReadyRead();
    void onError(QAbstractSocket::SocketError error);
    
private:
    QTcpSocket *socket;
    QString username;
};
cpp 复制代码
// ClientManager.cpp
#include "ClientManager.h"
#include <QJsonObject>
#include <QJsonDocument>

ClientManager::ClientManager(QObject *parent) : QObject(parent) {
    socket = new QTcpSocket(this);
    
    connect(socket, &QTcpSocket::connected, this, &ClientManager::onConnected);
    connect(socket, &QTcpSocket::readyRead, this, &ClientManager::onReadyRead);
    connect(socket, QOverload<QAbstractSocket::SocketError>::of(&QAbstractSocket::error),
            this, &ClientManager::onError);
}

void ClientManager::connectToServer(const QString &host, quint16 port) {
    socket->connectToHost(host, port);
}

void ClientManager::login(const QString &username, const QString &password) {
    this->username = username;
    
    QJsonObject json;
    json["type"] = "login";
    json["username"] = username;
    json["password"] = password;
    
    QJsonDocument doc(json);
    socket->write(doc.toJson(QJsonDocument::Compact) + '\n');
}

void ClientManager::sendMessage(const QString &to, const QString &message) {
    QJsonObject json;
    json["type"] = "message";
    json["from"] = username;
    json["to"] = to;
    json["content"] = message;
    
    QJsonDocument doc(json);
    socket->write(doc.toJson(QJsonDocument::Compact) + '\n');
}

void ClientManager::onConnected() {
    emit connected();
}

void ClientManager::onReadyRead() {
    while (socket->canReadLine()) {
        QByteArray data = socket->readLine();
        QJsonDocument doc = QJsonDocument::fromJson(data);
        if (doc.isNull()) continue;
        
        QJsonObject json = doc.object();
        QString type = json["type"].toString();
        
        if (type == "login") {
            bool success = json["success"].toBool();
            if (success) {
                emit loginSuccess();
            } else {
                emit loginFailed(json["reason"].toString());
            }
        } else if (type == "message") {
            QString from = json["from"].toString();
            QString content = json["content"].toString();
            emit messageReceived(from, content);
        }
    }
}

void ClientManager::onError(QAbstractSocket::SocketError error) {
    emit errorOccurred(socket->errorString());
}

5. 主程序入口

cpp 复制代码
// main.cpp
#include <QApplication>
#include "LoginWindow.h"
#include "MainWindow.h"
#include "ClientManager.h"

int main(int argc, char *argv[]) {
    QApplication app(argc, argv);
    
    ClientManager clientManager;
    LoginWindow loginWindow;
    
    // 连接登录信号
    QObject::connect(&loginWindow, &LoginWindow::loginRequested,
                     [&](const QString &username, const QString &password) {
        // 在实际应用中,这里应该连接服务器
        // 为简化演示,直接登录成功
        MainWindow *mainWindow = new MainWindow(username);
        mainWindow->show();
        loginWindow.hide();
    });
    
    // 显示登录窗口
    loginWindow.show();
    
    return app.exec();
}

参考项目 基于QT的仿QQ聊天系统 youwenfan.com/contentcsa/71899.html

界面美化建议

  1. CSS样式表:使用Qt的样式表功能美化界面
css 复制代码
/* 全局样式 */
QWidget {
    font-family: "Microsoft YaHei";
    font-size: 10pt;
}

/* 登录窗口 */
QLineEdit {
    padding: 8px;
    border: 1px solid #ccc;
    border-radius: 4px;
}

QPushButton {
    background-color: #4CAF50;
    color: white;
    padding: 8px;
    border: none;
    border-radius: 4px;
}

/* 主窗口 */
QListWidget {
    background-color: #f0f0f0;
    border: none;
}

QListWidget::item {
    padding: 10px;
    border-bottom: 1px solid #ddd;
}

/* 聊天窗口 */
QTextEdit {
    border: 1px solid #ddd;
    border-radius: 4px;
}
  1. 图标资源:为好友列表和按钮添加合适的图标
  2. 动画效果:在消息发送/接收时添加简单的动画效果

功能扩展建议

  1. 群聊功能:实现群组聊天功能
  2. 文件传输:添加文件传输功能
  3. 表情支持:支持发送表情符号
  4. 消息加密:实现端到端加密
  5. 语音/视频通话:添加实时音视频通信功能

这个仿QQ聊天系统实现了基本的登录、好友列表、一对一聊天功能,采用了Qt的信号槽机制实现组件间通信,使用JSON格式进行数据传输,界面设计简洁明了。可以根据实际需求进一步扩展功能和完善细节。

如果需要完整可编译的项目代码,请告知,我可以提供完整的Qt项目文件。

相关推荐
overFitBrain11 分钟前
数据结构-5(二叉树)
开发语言·数据结构·python
rookiesx22 分钟前
安装本地python文件到site-packages
开发语言·前端·python
m0_6873998434 分钟前
Ubuntu22 上,用C++ gSoap 创建一个简单的webservice
开发语言·c++
屁股割了还要学35 分钟前
【C语言进阶】一篇文章教会你文件的读写
c语言·开发语言·数据结构·c++·学习·青少年编程
微露清风40 分钟前
系统性学习C语言-第二十二讲-动态内存管理
c语言·开发语言·学习
钮钴禄·爱因斯晨41 分钟前
C语言|指针的应用
c语言·开发语言
Shingmc31 小时前
【C++】二叉搜索数
开发语言·c++
一个天蝎座 白勺 程序猿1 小时前
Python(32)Python内置函数全解析:30个核心函数的语法、案例与最佳实践
android·开发语言·python
MediaTea2 小时前
Python 库手册:ssl 加密通信模块
开发语言·网络·python·网络协议·ssl
wai歪why2 小时前
C语言:深入理解指针(5)
c语言·开发语言