QT6聊天室项目 功能性窗口设计

个人信息窗口

基本架构

基础信息显示设计

信号槽连接:对于个人信息窗口上的按钮功能,通过信号槽进行连接。目标是实现可修改信息

用户信息窗口

窗口架构

  • 申请好友:如果不是好友才可以使用
  • 下面三个按钮的逻辑具体实现在服务端实现后再进行具体实现

点击好友头像后,出现资料卡逻辑设置,借助槽函数实现

界面布局实现

会话详情窗口

窗口设计

  • 具体实现,分别以单聊和群聊两种的设计

界面布局实现

细节问题:名字截断逻辑实现

  • 设置可以放置名字的最大宽度
  • 计算文本的长度是多少

按钮和信号槽连接

选择好友窗口

架构设计,基于会话详情窗口的点击按钮,然后弹出一个新的会话窗

界面布局实现

添加群聊信号槽的实现

好友窗口设计,先实现一个好友信息,然后再实现排列的所有信息

细节实现:实现鼠标悬停状态下,用户信息颜色变深

细节分析:选择好友后,右侧窗口显示逻辑实现

左右侧好友增删操作的实现

程序崩溃退出:实现电点击左侧按钮,可以成功加入其到右侧,但是当点击右侧按钮的时候,程序异常退出

  1. 经调试,判断异常位置
  1. 根据上述代码,此处如果直接删除chooseFriendItem,一定会导致checkBox崩溃
  1. 解决:信号槽在执行完槽函数之后,内部还会做一些其他工作,需要首先释放对象,然后再delete,不可以直接delete

群聊会话详情窗口

窗口架构设计:仍在会话详情页面中进行显示

修改实现逻辑,弹出窗口的时候,需要分辨其是单聊还是群聊会话

群聊添加成员操作:获取成员信息,并按照4*4进行排列

  • 记录当前添加的行数与列数
  • 然后借助循环逻辑,实现4*4网格布局

实现代码

添加好友窗口

窗口布局设计

连接中间布局的添加按钮,通过信号槽,实现点击添加就可以弹出该窗口

单个好友搜索结果的实现

cpp 复制代码
///一个好友搜索的结果
FriendResultItem::FriendResultItem(const UserInfo &userInfo) :userInfo(userInfo)
{
    //1. 设置基本属性
    this->setFixedHeight(70);
    this->setSizePolicy(QSizePolicy::Expanding , QSizePolicy::Fixed);

    //2. 布局管理器
    QGridLayout*layout = new QGridLayout();
    layout->setVerticalSpacing(0);
    layout->setHorizontalSpacing(10);
    layout->setContentsMargins(0,0,20,0);
    this->setLayout(layout);

    //3.头像
    QPushButton*avatarBtn = new QPushButton();
    avatarBtn->setFixedSize(50,50);
    avatarBtn->setIconSize(QSize(50,50));
    avatarBtn->setIcon(userInfo.avatar);

    //4. 昵称
    QLabel* nameLabel = new QLabel();
    nameLabel->setFixedHeight(35);
    nameLabel->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed);
    nameLabel->setAlignment(Qt::AlignLeft | Qt::AlignVCenter);
    nameLabel->setStyleSheet("QLabel { font-size: 16px; font-weight: 700;}");
    nameLabel->setText(userInfo.nickname);

    // 5. 个性签名
    QLabel* descLabel = new QLabel();
    descLabel->setFixedHeight(35);
    descLabel->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed);
    descLabel->setAlignment(Qt::AlignLeft | Qt::AlignVCenter);
    descLabel->setStyleSheet("QLabel { font-size: 14px; }");
    descLabel->setText(userInfo.description);

    //6 添加好友按钮
    addBtn = new QPushButton();
    addBtn->setFixedSize(100,40);
    addBtn->setText("添加好友");
    QString btnStyle = "QPushButton { border: none; background-color: rgb(137, 217, 97); color: rgb(255, 255, 255); border-radius: 10px;} ";
    btnStyle += "QPushButton:pressed { background-color: rgb(200, 200, 200); }";
    addBtn->setStyleSheet(btnStyle);

    //添加到布局管理器中
    layout->addWidget(avatarBtn,0,0,2,1);
    layout->addWidget(nameLabel,0,1);
    layout->addWidget(descLabel,1,1);
    layout->addWidget(addBtn,0,2,2,1);

}

新增和清除好友逻辑

cpp 复制代码
///窗口中新增好友搜索结果
void AddFriendDialog::addResult(const UserInfo &userInfo)
{
    FriendResultItem*item = new FriendResultItem(userInfo);
    resultContainer->layout()->addWidget(item);
}

///清空界面所有结果
void AddFriendDialog::clear()
{
    //逻辑:从后往前遍历窗口元素,然后进行删除
    QVBoxLayout*layout = dynamic_cast<QVBoxLayout*>(resultContainer->layout());
    for(int i =layout->count()-1;i>=0;--i)
    {
        QLayoutItem*layoutItem = layout->takeAt(i);
        if(layoutItem==nullptr || layoutItem->widget()==nullptr)
        {
            continue;
        }
        delete layoutItem->widget();
    }
}

主页面搜索框中输入数据,同步显示到弹出窗口的搜索框中

搜索好友窗口

历史消息窗口

窗口设计

窗口弹出逻辑

历史消息切换逻辑实现:点击关键词和点击时间查询不同的结果

滚动区域设计实现

单条消息的设计实现 ,主要逻辑是利用工厂模式,构建不同的消息类型

窗口中添加和清除历史消息逻辑实现

最终效果实现

cpp 复制代码
///历史消息总窗口
HistoryMessageWidget::HistoryMessageWidget(QWidget *parent) :QDialog(parent)
{
    //1.窗口基本属性
    this->setFixedSize(600,600);
    this->setWindowTitle("历史消息");
    this->setWindowIcon(QIcon(":/resource/image/logo.png"));
    this->setStyleSheet("QWidget { background-color: rgb(255, 255, 255); }");
    this->setAttribute(Qt::WA_DeleteOnClose);

    //2.创建布局管理器
    QGridLayout*layout = new QGridLayout();
    layout->setSpacing(10);
    layout->setContentsMargins(30,30,30,0);
    this->setLayout(layout);

    //3.单选按钮
    keyRadioBtn = new QRadioButton();
    timeRadioBtn = new QRadioButton();
    keyRadioBtn->setText("按关键字查询");
    timeRadioBtn->setText("按时间查询");
    keyRadioBtn->setChecked(true); //默认按照关键字查询
    layout->addWidget(keyRadioBtn,0,0,1,2);
    layout->addWidget(timeRadioBtn,0,2,1,2);

    //4.搜索框
    searchEdit = new QLineEdit();
    searchEdit->setFixedHeight(50);
    searchEdit->setSizePolicy(QSizePolicy::Expanding,QSizePolicy::Fixed);
    searchEdit->setPlaceholderText("要搜索的关键词");
    searchEdit->setStyleSheet("QLineEdit { border: none; border-radius: 10px; background-color: rgb(240, 240, 240); font-size: 16px; padding-left: 10px; }");
    layout->addWidget(searchEdit,1,0,1,8);

    //5.搜索按钮
    QPushButton*searchBtn = new QPushButton();
    searchBtn->setFixedSize(50,50);
    searchBtn->setSizePolicy(QSizePolicy::Fixed,QSizePolicy::Fixed);
    searchBtn->setIconSize(QSize(30, 30));
    searchBtn->setIcon(QIcon(":/resource/image/search.png"));
    QString btnStyle = "QPushButton { border: none; background-color: rgb(240, 240, 240); border-radius: 10px; }";
    btnStyle += "QPushButton:pressed { background-color: rgb(220, 220, 220); }";
    searchBtn->setStyleSheet(btnStyle);
    layout->addWidget(searchBtn, 1, 8, 1, 1);

    //6. 时间控件
    QLabel*begTag = new QLabel();
    begTag->setText("开始时间");
    QLabel*endTag = new QLabel();
    endTag->setText("结束时间");
    begTimeEdit = new QDateTimeEdit();
    endTimeEdit = new QDateTimeEdit();

    begTimeEdit->setDisplayFormat("yyyy-MM-dd hh:mm");
    endTimeEdit->setDisplayFormat("yyyy-MM-dd hh:mm");
    begTimeEdit->setFixedHeight(40);
    endTimeEdit->setFixedHeight(40);
    begTag->hide();
    endTag->hide();
    begTimeEdit->hide();
    endTimeEdit->hide();

    //7. 滚动区域
    initScrollArea(layout);

    //8. 槽函数
    connect(keyRadioBtn,&QRadioButton::clicked,this,[=](){
        //时间控件隐藏
        layout->removeWidget(begTag);
        layout->removeWidget(begTimeEdit);
        layout->removeWidget(endTag);
        layout->removeWidget(endTimeEdit);
        begTag->hide();
        begTimeEdit->hide();
        endTag->hide();
        endTimeEdit->hide();

        //关键词搜索框加入布局
        layout->addWidget(searchEdit,1,0,1,8);
        searchEdit->show();
    });
    connect(timeRadioBtn,&QRadioButton::clicked,this,[=](){
        //关键字搜索框隐藏
        layout->removeWidget(searchEdit);
        searchEdit->hide();

        //时间控件添加到布局管理器中
        layout->addWidget(begTag,1,0,1,1);
        layout->addWidget(begTimeEdit,1,1,1,3);
        layout->addWidget(endTag,1,4,1,1);
        layout->addWidget(endTimeEdit,1,5,1,3);
        begTag->show();
        begTimeEdit->show();
        endTag->show();
        endTimeEdit->show();
    });

    //测试
#if TEST_UI
    for(int i =0;i<30;++i)
    {
        UserInfo sender;
        sender.userId = "";
        sender.nickname = "张三"+QString::number(i);
        sender.avatar = QIcon(":/resource/image/defaultAvatar.png");
        sender.description ="";
        // Message message = Message::makeMessage(TEXT_TYPE,"",sender,QString("测试消息"+QString::number(i).toUtf8(),"");
        Message message = Message::makeMessage(TEXT_TYPE, "", sender, QString("消息内容" + QString::number(i)).toUtf8(), "");
        this->addHistoryMessage(message);
    }
#endif
}

登陆窗口

窗口总体布局

登录窗口弹出逻辑分析

  • 修改主函数逻辑,按照规则弹出登录窗口

注册与登录模式的切换,借助槽函数实现

账号登录与手机号登录切换逻辑实现

登录和注册窗口切换逻辑实现

用户名和手机号登录窗口切换逻辑分析

全局通知窗口

页面布局逻辑

全局通知窗口实现

cpp 复制代码
Toast::Toast(const QString &text)
{
    //1.窗口基本属性
    this->setFixedSize(500,100);
    this->setWindowTitle("消息通知");
    this->setWindowIcon(QIcon(":/resource/image/logo.png"));
    this->setAttribute(Qt::WA_DeleteOnClose);
    this->setStyleSheet("QDialog {background-color:rgb(255,255,255);}");
    this->setWindowFlags(Qt::FramelessWindowHint);

    //2. 窗口尺寸
    QScreen*screen = QApplication::primaryScreen();
    int width = screen->size().width();
    int height = screen->size().height();
    int x = (width - this->width())/2;
    int y = height - this->height()-100;
    this->move(x,y);

    //3. 布局管理器
    QVBoxLayout*layout = new QVBoxLayout();
    layout->setSpacing(0);
    layout->setContentsMargins(0,0,0,0);
    this->setLayout(layout);

    //4. 显示文本
    QLabel*label = new QLabel();
    label->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
    label->setAlignment(Qt::AlignCenter);
    label->setStyleSheet("QLabel { font-size: 32px; }");
    label->setText(text);
    layout->addWidget(label);

    //5. 定时关闭
    QTimer*timer = new QTimer(this);
    connect(timer,&QTimer::timeout,this,[=](){
        timer->stop();
        this->close();
    });
    timer->start(2000);
}

void Toast::showMessage(const QString &text)
{
    Toast*toast = new Toast(text);
    toast->show();
}
相关推荐
Beau_Will13 分钟前
数据结构-树状数组专题(1)
数据结构·c++·算法
hunandede1 小时前
av_image_get_buffer_size 和 av_image_fill_arrays
c++
怀澈1222 小时前
高性能服务器模型之Reactor(单线程版本)
linux·服务器·网络·c++
chnming19873 小时前
STL关联式容器之set
开发语言·c++
威桑3 小时前
MinGW 与 MSVC 的区别与联系及相关特性分析
c++·mingw·msvc
熬夜学编程的小王3 小时前
【C++篇】深度解析 C++ List 容器:底层设计与实现揭秘
开发语言·数据结构·c++·stl·list
yigan_Eins3 小时前
【数论】莫比乌斯函数及其反演
c++·经验分享·算法
Mr.133 小时前
什么是 C++ 中的初始化列表?它的作用是什么?初始化列表和在构造函数体内赋值有什么区别?
开发语言·c++
阿史大杯茶3 小时前
AtCoder Beginner Contest 381(ABCDEF 题)视频讲解
数据结构·c++·算法
C++忠实粉丝3 小时前
计算机网络socket编程(3)_UDP网络编程实现简单聊天室
linux·网络·c++·网络协议·计算机网络·udp