聊天项目(21) 滚动聊天布局设计

滚动聊天布局设计

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

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

代码实现

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

  1. class ChatView: public QWidget
  2. {
  3. Q_OBJECT
  4. public:
  5. ChatView(QWidget *parent = Q_NULLPTR);
  6. void appendChatItem(QWidget *item); //尾插
  7. void prependChatItem(QWidget *item); //头插
  8. void insertChatItem(QWidget *before, QWidget *item);//中间插
  9. protected:
  10. bool eventFilter(QObject *o, QEvent *e) override;
  11. void paintEvent(QPaintEvent *event) override;
  12. private slots:
  13. void onVScrollBarMoved(int min, int max);
  14. private:
  15. void initStyleSheet();
  16. private:
  17. //QWidget *m_pCenterWidget;
  18. QVBoxLayout *m_pVl;
  19. QScrollArea *m_pScrollArea;
  20. bool isAppended;
  21. };

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

  1. ChatView::ChatView(QWidget *parent) : QWidget(parent)
  2. , isAppended(false)
  3. {
  4. QVBoxLayout *pMainLayout = new QVBoxLayout();
  5. this->setLayout(pMainLayout);
  6. pMainLayout->setMargin(0);
  7. m_pScrollArea = new QScrollArea();
  8. m_pScrollArea->setObjectName("chat_area");
  9. pMainLayout->addWidget(m_pScrollArea);
  10. QWidget *w = new QWidget(this);
  11. w->setObjectName("chat_bg");
  12. w->setAutoFillBackground(true);
  13. QVBoxLayout *pVLayout_1 = new QVBoxLayout();
  14. pVLayout_1->addWidget(new QWidget(), 100000);
  15. w->setLayout(pVLayout_1);
  16. m_pScrollArea->setWidget(w);
  17. m_pScrollArea->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
  18. QScrollBar *pVScrollBar = m_pScrollArea->verticalScrollBar();
  19. connect(pVScrollBar, &QScrollBar::rangeChanged,this, &ChatView::onVScrollBarMoved);
  20. //把垂直ScrollBar放到上边 而不是原来的并排
  21. QHBoxLayout *pHLayout_2 = new QHBoxLayout();
  22. pHLayout_2->addWidget(pVScrollBar, 0, Qt::AlignRight);
  23. pHLayout_2->setMargin(0);
  24. m_pScrollArea->setLayout(pHLayout_2);
  25. pVScrollBar->setHidden(true);
  26. m_pScrollArea->setWidgetResizable(true);
  27. m_pScrollArea->installEventFilter(this);
  28. initStyleSheet();
  29. }

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

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

重写事件过滤器

  1. bool ChatView::eventFilter(QObject *o, QEvent *e)
  2. {
  3. /*if(e->type() == QEvent::Resize && o == )
  4. {
  5. }
  6. else */if(e->type() == QEvent::Enter && o == m_pScrollArea)
  7. {
  8. m_pScrollArea->verticalScrollBar()->setHidden(m_pScrollArea->verticalScrollBar()->maximum() == 0);
  9. }
  10. else if(e->type() == QEvent::Leave && o == m_pScrollArea)
  11. {
  12. m_pScrollArea->verticalScrollBar()->setHidden(true);
  13. }
  14. return QWidget::eventFilter(o, e);
  15. }

重写paintEvent支持子类绘制

  1. void ChatView::paintEvent(QPaintEvent *event)
  2. {
  3. QStyleOption opt;
  4. opt.init(this);
  5. QPainter p(this);
  6. style()->drawPrimitive(QStyle::PE_Widget, &opt, &p, this);
  7. }

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

  1. void ChatView::onVScrollBarMoved(int min, int max)
  2. {
  3. if(isAppended) //添加item可能调用多次
  4. {
  5. QScrollBar *pVScrollBar = m_pScrollArea->verticalScrollBar();
  6. pVScrollBar->setSliderPosition(pVScrollBar->maximum());
  7. //500毫秒内可能调用多次
  8. QTimer::singleShot(500, [this]()
  9. {
  10. isAppended = false;
  11. });
  12. }
  13. }

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

视频链接

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

源码链接

https://gitee.com/secondtonone1/llfcchat

热门评论

热门文章

  1. slice介绍和使用

    喜欢(521) 浏览(1880)
  2. 解密定时器的实现细节

    喜欢(566) 浏览(2125)
  3. C++ 类的继承封装和多态

    喜欢(588) 浏览(2960)
  4. Linux环境搭建和编码

    喜欢(594) 浏览(6419)
  5. windows环境搭建和vscode配置

    喜欢(587) 浏览(1801)

最新评论

  1. 解决博客回复区被脚本注入的问题 secondtonone1:走到现在我忽然明白一个道理,无论工作也好生活也罢,最重要的是开心,即使一份安稳的工作不能给我带来事业上的积累也要合理的舍弃,所以我还是想去做喜欢的方向。
  2. slice介绍和使用 恋恋风辰:切片作为引用类型极大的提高了数据传递的效率和性能,但也要注意切片的浅拷贝隐患,算是一把双刃剑,这世间的常态就是在两极之间寻求一种稳定。
  3. 泛型算法的定制操作 secondtonone1:lambda和bind是C11新增的利器,善于利用这两个机制可以极大地提升编程安全性和效率。
  4. C++ 虚函数表原理和类成员内存分布 WangQi888888:class Test{ int m; int b; }中b成员是int,为什么在内存中只占了1个字节。不应该是4个字节吗?是不是int应该改为char。这样的话就会符合图上说明的情况
  5. 类和对象 陈宇航:支持!!!!

个人公众号

个人微信