首页 > 编程语言 >C++全栈聊天项目(21) 滚动聊天布局设计

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

时间:2024-06-08 11:32:43浏览次数:22  
标签:ChatView void C++ item pScrollArea 聊天 QWidget pVScrollBar 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

标签:ChatView,void,C++,item,pScrollArea,聊天,QWidget,pVScrollBar,21
From: https://blog.csdn.net/secondtonone1/article/details/139544172

相关文章

  • 「漏洞复现」锐捷校园网自助服务系统 login_judge.jsf 任意文件读取漏洞(XVE-2024-211
    0x01 免责声明请勿利用文章内的相关技术从事非法测试,由于传播、利用此文所提供的信息而造成的任何直接或者间接的后果及损失,均由使用者本人负责,作者不为此承担任何责任。工具来自网络,安全性自测,如有侵权请联系删除。本次测试仅供学习使用,如若非法他用,与平台和本文作者无关,需......
  • C++入门 初始化列表 & 隐式类型转换
    目录初始化列表构造函数体赋值初始化列表格式初始化列表特性每个成员变量在初始化列表中只能出现一次类中以下成员必须初始化尽量使用初始化列表初始化数组初始化 声明次序就是初始化顺序多参数初始化列表再谈隐式类型转换拷贝引用explicit关键字定义用法缺......
  • P7219 [JOISC2020] 星座 3 题解
    会发现题目的坐标其实是平面直角坐标系。我们按\(y\)坐标从小到大考虑所有的星星,假设当前考虑到了星星\(i\)。我们先计算出之前所有能够影响到\(i\)的星星的代价和为\(cost\)(可以用树状数组维护)。然后分类讨论。若\(c_i\lecost\),那么肯定直接将\(i\)直接涂黑,因为它更......
  • Pyramid Vision Transformer, PVT(ICCV 2021)原理与代码解读
    paper:PyramidVisionTransformer:AVersatileBackboneforDensePredictionwithoutConvolutionsofficialimplementation:GitHub-whai362/PVT:OfficialimplementationofPVTseries存在的问题现有的VisionTransformer(ViT)主要设计用于图像分类任务,难以直接用......
  • 【C++练级之路】【Lv.23】C++11——可变参数模板、lambda表达式和函数包装器
    快乐的流畅:个人主页个人专栏:《算法神殿》《数据结构世界》《进击的C++》远方有一堆篝火,在为久候之人燃烧!文章目录一、可变参数模板1.1参数包的概念1.2参数包的展开1.3emplace系列二、lambda表达式2.1lambda的格式2.2捕捉列表2.3lambda的原理2.4......
  • 类和对象(二)(C++)
    初始化列表classDate{public:Date(intyear,intmonth,intday){_year=year;_month=month;_day=day;}private:int_year;int_month;int_day;};虽然上述构造函数调用之后,对象中已经有了一个初......
  • 07c/c++面向对象
    07C/c++零碎语法目录文章目录07C/c++零碎语法C1.封装2.继承3.多态C++4.1封装4.1.1封装的意义5.继承5.1继承的基本语法5.2继承方式5.3继承中的对象模型5.4继承中构造和析构顺序5.5继承同名成员处理方式5.6继承同名静态成员处理方式5.7菱形继承C1.封......
  • c++类与对象
    classBook{public:charname;intpages;voidprintpages();}voidprintpages(){std::cout<<"书的页数"<<endl;}在定义类的属性和方法时可以选择1.public:公有成员(在程序中类的外部是可访问的)。2.protected:受保护成员(在类的外部是不可访问的,甚......
  • c++的面对对象 的 虚函数
    #include<iostream>#include<string>classAnimal{public:virtualvoidmakeSound()=0;//纯虚函数,所有的动物都应该提供自己的叫声};classDog:publicAnimal{public:voidmakeSound()override{std::cout<<"Woof!"<&l......
  • 【C++修行之道】类和对象(五)日期类的实现、const成员、取地址及const和取地址操作符重
    目录一、日期类的实现Date.h 1.1GetMonthDay函数(获取某年某月的天数) 问:这个函数为什么不和其他的函数一样放在Date.cpp文件中实现呢?1.2CheckDate函数(检查日期有效性)、Print函数(打印日期)1.3实现日期类的逻辑运算符重载<运算符的重载 ==运算符重载其他运算符重载......