设计思路
系统需要包含以下核心功能:
- 用户登录界面
- 好友列表展示
- 一对一聊天功能
- 消息发送与接收
- 消息历史记录
实现方案
核心类设计
LoginWindow
:登录界面MainWindow
:主界面(包含好友列表和聊天区域)ChatDialog
:聊天对话框ClientManager
:客户端管理类(处理网络通信)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 ¤tUser, 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 ¤tUser, 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
界面美化建议
- 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;
}
- 图标资源:为好友列表和按钮添加合适的图标
- 动画效果:在消息发送/接收时添加简单的动画效果
功能扩展建议
- 群聊功能:实现群组聊天功能
- 文件传输:添加文件传输功能
- 表情支持:支持发送表情符号
- 消息加密:实现端到端加密
- 语音/视频通话:添加实时音视频通信功能
这个仿QQ聊天系统实现了基本的登录、好友列表、一对一聊天功能,采用了Qt的信号槽机制实现组件间通信,使用JSON格式进行数据传输,界面设计简洁明了。可以根据实际需求进一步扩展功能和完善细节。
如果需要完整可编译的项目代码,请告知,我可以提供完整的Qt项目文件。