C++全栈聊天项目(21) 滚动聊天布局设计

滚动聊天布局设计

我们的聊天布局如下图
最外层的是一个chatview(黑色), chatview内部在添加一个MainLayout(蓝色),MainLayout内部添加一个scrollarea(红色),scrollarea内部包含一个widget(绿色),同时也包含一个HLayout(紫色)用来浮动显示滚动条。widget内部包含一个垂直布局Vlayout(黄色),黄色布局内部包含一个粉色的widget,widget占据拉伸比一万,保证充满整个布局。

https://cdn.llfc.club/layoutpic.png

代码实现

我们对照上面的图手写代码,在项目中添加ChatView类,然后先实现类的声明

class ChatView: public QWidget
{
    Q_OBJECT
public:
    ChatView(QWidget *parent = Q_NULLPTR);
    void appendChatItem(QWidget *item);                 //尾插
    void prependChatItem(QWidget *item);                //头插
    void insertChatItem(QWidget *before, QWidget *item);//中间插
protected:
    bool eventFilter(QObject *o, QEvent *e) override;
    void paintEvent(QPaintEvent *event) override;
private slots:
    void onVScrollBarMoved(int min, int max);
private:
    void initStyleSheet();
private:
    //QWidget *m_pCenterWidget;
    QVBoxLayout *m_pVl;
    QScrollArea *m_pScrollArea;
    bool isAppended;
};

接下来实现其函数定义, 先实现构造函数

ChatView::ChatView(QWidget *parent)  : QWidget(parent)
  , isAppended(false)
{
    QVBoxLayout *pMainLayout = new QVBoxLayout();
    this->setLayout(pMainLayout);
    pMainLayout->setMargin(0);

    m_pScrollArea = new QScrollArea();
    m_pScrollArea->setObjectName("chat_area");
    pMainLayout->addWidget(m_pScrollArea);

    QWidget *w = new QWidget(this);
    w->setObjectName("chat_bg");
    w->setAutoFillBackground(true);

    QVBoxLayout *pVLayout_1 = new QVBoxLayout();
    pVLayout_1->addWidget(new QWidget(), 100000);
    w->setLayout(pVLayout_1);
    m_pScrollArea->setWidget(w);

    m_pScrollArea->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
    QScrollBar *pVScrollBar = m_pScrollArea->verticalScrollBar();
    connect(pVScrollBar, &QScrollBar::rangeChanged,this, &ChatView::onVScrollBarMoved);

    //把垂直ScrollBar放到上边 而不是原来的并排
    QHBoxLayout *pHLayout_2 = new QHBoxLayout();
    pHLayout_2->addWidget(pVScrollBar, 0, Qt::AlignRight);
    pHLayout_2->setMargin(0);
    m_pScrollArea->setLayout(pHLayout_2);
    pVScrollBar->setHidden(true);

    m_pScrollArea->setWidgetResizable(true);
    m_pScrollArea->installEventFilter(this);
    initStyleSheet();
}

再实现添加条目到聊天背景

void ChatView::appendChatItem(QWidget *item)
{
    QVBoxLayout *vl = qobject_cast<QVBoxLayout *>(m_pScrollArea->widget()->layout());
    vl->insertWidget(vl->count()-1, item);
    isAppended = true;
}

重写事件过滤器

bool ChatView::eventFilter(QObject *o, QEvent *e)
{
    /*if(e->type() == QEvent::Resize && o == )
    {

    }
    else */if(e->type() == QEvent::Enter && o == m_pScrollArea)
    {
        m_pScrollArea->verticalScrollBar()->setHidden(m_pScrollArea->verticalScrollBar()->maximum() == 0);
    }
    else if(e->type() == QEvent::Leave && o == m_pScrollArea)
    {
         m_pScrollArea->verticalScrollBar()->setHidden(true);
    }
    return QWidget::eventFilter(o, e);
}

重写paintEvent支持子类绘制

void ChatView::paintEvent(QPaintEvent *event)
{
    QStyleOption opt;
    opt.init(this);
    QPainter p(this);
    style()->drawPrimitive(QStyle::PE_Widget, &opt, &p, this);
}

监听滚动区域变化的槽函数

void ChatView::onVScrollBarMoved(int min, int max)
{
    if(isAppended) //添加item可能调用多次
    {
        QScrollBar *pVScrollBar = m_pScrollArea->verticalScrollBar();
        pVScrollBar->setSliderPosition(pVScrollBar->maximum());
        //500毫秒内可能调用多次
        QTimer::singleShot(500, [this]()
        {
            isAppended = false;
        });
    }
}

本节先到这里,完成聊天布局基本的构造

视频链接

https://www.bilibili.com/video/BV1xz421h7Ad/?vd_source=8be9e83424c2ed2c9b2a3ed1d01385e9

源码链接

https://gitee.com/secondtonone1/llfcchat

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/690807.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

【Redis】Redis经典问题:缓存穿透、缓存击穿、缓存雪崩

目录 缓存的处理流程缓存穿透解释产生原因解决方案1.针对不存在的数据也进行缓存2.设置合适的缓存过期时间3. 对缓存访问进行限流和降级4. 接口层增加校验5. 布隆过滤器原理优点缺点关于扩容其他使用场景SpringBoot 整合 布隆过滤器 缓存击穿产生原因解决方案1.设置热点数据永不…

Swift 序列(Sequence)排序面面俱到 - 从过去到现在(二)

概览 在上篇 Swift 序列(Sequence)排序面面俱到 - 从过去到现在(一)博文中,我们讨论了 Swift 语言中序列和集合元素排序的一些基本知识,我们还给出了以自定义类型中任意属性排序的“康庄大道”。 不过在实际的撸码场景中,我们往往需要的是“多属性”同时参与到排序的考…

STM32F103C8T6基于HAL库移植uC/OS-III

文章目录 一、建立STM32CubeMX工程二、移植1、 uC/OS-III源码2、移植过程 三、配置相关代码1、bsp.c和bsp.h2、main.c3、修改启动代码4、修改app_cfg.h文件5、修改includes.h文件6、修改lib_cfg.h文件 四、编译与烧录总结参考资料 学习嵌入式实时操作系统&#xff08;RTOS&…

Swift 序列(Sequence)排序面面俱到 - 从过去到现在(一)

概览 在任何语言中对序列(或集合)元素的排序无疑是一种司空见惯的常规操作,在 Swift 语言里自然也不例外。序列排序看似简单,实则“暗藏玄机”。 要想真正掌握 Swift 语言中对排序的“各种姿势”,我们还得从长计议。不如就先从最简单的排序基本功开始聊起吧。 在本篇博…

9行超强代码用Python工具快速获取放假日期

9行超强代码用Python工具快速获取放假日期 在很多场景下,我们需要获知国内具体的节假日安排情况,而国内每一年具体的放假安排以及调休情况,都依赖于国务院发布的具体公告,如果不想自己手动整理相关数据的话,我们可以用Python来快速获取最新的放假日期. 可以通过调用公开的 API…

spark-3.5.1+Hadoop 3.4.0+Hive4.0 分布式集群 安装配置

Hadoop安装参考: Hadoop 3.4.0HBase2.5.8ZooKeeper3.8.4Hive4.0Sqoop 分布式高可用集群部署安装 大数据系列二-CSDN博客 一 下载:Downloads | Apache Spark 1 下载Maven – Welcome to Apache Maven # maven安装及配置教程 wget https://dlcdn.apache.org/maven/maven-3/3.8…

App UI 风格创新无限

App UI 风格创新无限

如何理解与学习数学分析——第二部分——数学分析中的基本概念——第8章——可微性

第2 部分&#xff1a;数学分析中的基本概念 (Concepts in Analysis) 8. 可微性(Differentiability) 本章讨论梯度(gradients)/斜率(slopes)和切线(tangent)&#xff0c;指出常见的误解并解释如何避免这些误解。将可微性的定义与图形表示联系起来&#xff0c;展示如何将其应用…

什么是2+1退休模式?什么是链动2+1模式?

21退休模式又称链动21模式&#xff0c;主要是建立团队模式&#xff0c;同时快速提升销量。是目前成熟模式中裂变速度最快的模式。21退休模式合理合规&#xff0c;同时激励用户公司的利润分享机制&#xff0c;让您在享受购物折扣的同时&#xff0c;也能促进并获得客观收益。 模…

大模型多轮问答的两种方式

前言 大模型的多轮问答难点就是在于如何精确识别用户最新的提问的真实意图&#xff0c;而在常见的使用大模型进行多轮对话方式中&#xff0c;我接触到的只有两种方式&#xff1a; 一种是简单地直接使用 user 和 assistant 两个角色将一问一答的会话内容喂给大模型&#xff0c…

Large-Scale LiDAR Consistent Mapping usingHierarchical LiDAR Bundle Adjustment

1. 代码地址 GitHub - hku-mars/HBA: [RAL 2023] A globally consistent LiDAR map optimization module 2. 摘要 重建精确一致的大规模激光雷达点云地图对于机器人应用至关重要。现有的基于位姿图优化的解决方案&#xff0c;尽管它在时间方面是有效的&#xff0c;但不能直接…

【python】python电影评论数据抓取分析可视化(源码+数据+课程论文)【独一无二】

&#x1f449;博__主&#x1f448;&#xff1a;米码收割机 &#x1f449;技__能&#x1f448;&#xff1a;C/Python语言 &#x1f449;公众号&#x1f448;&#xff1a;测试开发自动化【获取源码商业合作】 &#x1f449;荣__誉&#x1f448;&#xff1a;阿里云博客专家博主、5…

Windows系统问题

Windows系统问题 一、补丁更新提示&#xff1a;0x80070643问题&#xff1a;解决方法&#xff1a;1.以管理员权限运行【cmd】。2.禁用 【Windows RE】&#xff0c;请运行reagentc /disable。3.回收【Windows RE】恢复分区空间。4.准备新的【Windows RE】恢复分区空间。5.配置并启…

如何检测UV胶的均匀性?

如何检测UV胶的均匀性&#xff1f; 检测UV胶的均匀性可以通过以下几种方法来实现&#xff1a; 肉眼目视检查&#xff1a; 这是最简单直接的方法。将UV胶涂在表面上&#xff0c;使用裸眼观察胶层的表面。特别注意是否存在气泡、颜色不均匀、裂纹或其他明显的不均匀性。如凹凸不…

从零开始实现自己的串口调试助手(9)-重置多文本框,保存/载入指令集

重置多文本框 添加多文本控件列表 在构造函数中把我们需要操作的控件归类到对应列表之中 //创建多文本存放数组 - 存放那三列内容 checkBox lineEdi btnfor(int i1;i<9;i){// 添加到按钮数组QString btnName QString("pushButton_t%1").arg(i); //构建对应控件名…

独享IP VS 原生IP,二者的区别与定义详解

原生IP&#xff1a;原生IP是指由Internet服务提供商&#xff08;ISP&#xff09;直接分配给用户的IP地址&#xff0c;这些IP地址通常反映了用户的实际地理位置和网络连接。原生IP是用户在其所在地区或国家使用的真实IP地址&#xff0c;与用户的物理位置直接相关。在跨境电商中&…

汉中门禁系统设备多少钱,门禁系统报价单

汉中门禁系统设备多少钱&#xff0c;门禁系统报价单 门禁系统设备存在普通与智能之分&#xff0c;其价格差异颇大。以下是一些国内品牌的门禁系统价格&#xff1b; 以上只是部分国内品牌门禁机设备的报价&#xff0c;仅供参考&#xff0c;能看出目前市面上&#xff0c;海…

Freetype 介绍和使用

目录 一、矢量字体引入 二、Freetype 介绍 1.给定一个字符&#xff0c;怎么在字体文件中找到它的关键点&#xff1f; 2.文字显示过程 3.如何使用 freetype 库 三、在 LCD 上显示一个矢量字体 1.使用 wchar_t 获得字符的 UNICODE 值 2.使用 freetype 得到位图 3.在屏幕上…

Java——数组排序

一、排序介绍 1、排序的概念 排序是将多个数据按照指定的顺序进行排列的过程。 2、排序的种类 排序可以分为两大类&#xff1a;内部排序和外部排序。 3、内部排序和外部排序 1&#xff09;内部排序 内部排序是指数据在内存中进行排序&#xff0c;适用于数据量较小的情况…

一个 buffer 使用的负反馈实例

端到端拥塞控制其实就是负反馈的实施。典型的做法是识别到一系列标志性事件&#xff0c;比如丢包&#xff0c;时延增加等&#xff0c;然后对这些事件做反应&#xff0c;进而形成负反馈&#xff0c;但 inflight 守恒是一种完全不同的做法&#xff0c;它将负反馈平铺到了整个传输…