聊天项目(20) 动态加载聊天列表

聊天列表动态加载

如果要动态加载聊天列表内容,我们可以在列表的滚动区域捕获鼠标滑轮事件,并且在滚动到底部的时候我们发送一个加载聊天用户的信号

  1. bool ChatUserList::eventFilter(QObject *watched, QEvent *event)
  2. {
  3. // 检查事件是否是鼠标悬浮进入或离开
  4. if (watched == this->viewport()) {
  5. if (event->type() == QEvent::Enter) {
  6. // 鼠标悬浮,显示滚动条
  7. this->setVerticalScrollBarPolicy(Qt::ScrollBarAsNeeded);
  8. } else if (event->type() == QEvent::Leave) {
  9. // 鼠标离开,隐藏滚动条
  10. this->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
  11. }
  12. }
  13. // 检查事件是否是鼠标滚轮事件
  14. if (watched == this->viewport() && event->type() == QEvent::Wheel) {
  15. QWheelEvent *wheelEvent = static_cast<QWheelEvent*>(event);
  16. int numDegrees = wheelEvent->angleDelta().y() / 8;
  17. int numSteps = numDegrees / 15; // 计算滚动步数
  18. // 设置滚动幅度
  19. this->verticalScrollBar()->setValue(this->verticalScrollBar()->value() - numSteps);
  20. // 检查是否滚动到底部
  21. QScrollBar *scrollBar = this->verticalScrollBar();
  22. int maxScrollValue = scrollBar->maximum();
  23. int currentValue = scrollBar->value();
  24. //int pageSize = 10; // 每页加载的联系人数量
  25. if (maxScrollValue - currentValue <= 0) {
  26. // 滚动到底部,加载新的联系人
  27. qDebug()<<"load more chat user";
  28. //发送信号通知聊天界面加载更多聊天内容
  29. emit sig_loading_chat_user();
  30. }
  31. return true; // 停止事件传递
  32. }
  33. return QListWidget::eventFilter(watched, event);
  34. }

回到ChatDialog类里添加槽函数

  1. void ChatDialog::slot_loading_chat_user()
  2. {
  3. if(_b_loading){
  4. return;
  5. }
  6. _b_loading = true;
  7. LoadingDlg *loadingDialog = new LoadingDlg(this);
  8. loadingDialog->setModal(true);
  9. loadingDialog->show();
  10. qDebug() << "add new data to list.....";
  11. addChatUserList();
  12. // 加载完成后关闭对话框
  13. loadingDialog->deleteLater();
  14. _b_loading = false;
  15. }

槽函数中我们添加了LoadingDlg类,这个类也是个QT 设计师界面类,ui如下

https://cdn.llfc.club/1717637779912.jpg

添加stackwidget管理界面

ChatDialog界面里添加stackedWidget,然后添加两个页面

https://cdn.llfc.club/1717639561119.jpg

回头我们将这两个界面升级为我们自定义的界面

我们先添加一个自定义的QT设计师界面类ChatPage,然后将原来放在ChatDialog.ui中的chat_data_wid这个widget移动到ChatPage中ui布局如下

https://cdn.llfc.club/1717640323397.jpg

布局属性如下

https://cdn.llfc.club/1717640426705.jpg

然后我们将ChatDialog.ui中的chat_page 升级为ChatPage。

接着我们将ChatPage中的一些控件比如emo_lb, file_lb升级为ClickedLabel, receive_btn, send_btn升级为ClickedBtn

如下图:

https://cdn.llfc.club/1717644080174.jpg

然后我们在ChatPage的构造函数中添加按钮样式的编写

  1. ChatPage::ChatPage(QWidget *parent) :
  2. QWidget(parent),
  3. ui(new Ui::ChatPage)
  4. {
  5. ui->setupUi(this);
  6. //设置按钮样式
  7. ui->receive_btn->SetState("normal","hover","press");
  8. ui->send_btn->SetState("normal","hover","press");
  9. //设置图标样式
  10. ui->emo_lb->SetState("normal","hover","press","normal","hover","press");
  11. ui->file_lb->SetState("normal","hover","press","normal","hover","press");
  12. }

因为我们继承了QWidget,我们想实现样式更新,需要重写paintEvent

  1. void ChatPage::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. }

类似的,我们的ListItemBase

  1. void ListItemBase::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. }

ClickedLabel完善

我们希望ClickedLabel在按下的时候显示按下状态的资源,在抬起的时候显示抬起的资源,所以修改按下事件和抬起事件

  1. void ClickedLabel::mousePressEvent(QMouseEvent *event)
  2. {
  3. if (event->button() == Qt::LeftButton) {
  4. if(_curstate == ClickLbState::Normal){
  5. qDebug()<<"clicked , change to selected hover: "<< _selected_hover;
  6. _curstate = ClickLbState::Selected;
  7. setProperty("state",_selected_press);
  8. repolish(this);
  9. update();
  10. }else{
  11. qDebug()<<"clicked , change to normal hover: "<< _normal_hover;
  12. _curstate = ClickLbState::Normal;
  13. setProperty("state",_normal_press);
  14. repolish(this);
  15. update();
  16. }
  17. return;
  18. }
  19. // 调用基类的mousePressEvent以保证正常的事件处理
  20. QLabel::mousePressEvent(event);
  21. }

抬起事件

  1. void ClickedLabel::mouseReleaseEvent(QMouseEvent *event)
  2. {
  3. if (event->button() == Qt::LeftButton) {
  4. if(_curstate == ClickLbState::Normal){
  5. // qDebug()<<"ReleaseEvent , change to normal hover: "<< _normal_hover;
  6. setProperty("state",_normal_hover);
  7. repolish(this);
  8. update();
  9. }else{
  10. // qDebug()<<"ReleaseEvent , change to select hover: "<< _selected_hover;
  11. setProperty("state",_selected_hover);
  12. repolish(this);
  13. update();
  14. }
  15. emit clicked();
  16. return;
  17. }
  18. // 调用基类的mousePressEvent以保证正常的事件处理
  19. QLabel::mousePressEvent(event);
  20. }

qss美化

我们添加qss美化一下

  1. LoadingDlg{
  2. background: #f2eada;
  3. }
  4. #title_lb{
  5. font-family: "Microsoft YaHei";
  6. font-size: 18px;
  7. font-weight: normal;
  8. }
  9. #chatEdit{
  10. background: #ffffff;
  11. border: none; /* 隐藏边框 */
  12. font-family: "Microsoft YaHei"; /* 设置字体 */
  13. font-size: 18px; /* 设置字体大小 */
  14. padding: 5px; /* 设置内边距 */
  15. }
  16. #send_wid{
  17. background: #ffffff;
  18. border: none; /* 隐藏边框 */
  19. }
  20. #add_btn[state='normal']{
  21. border-image: url(:/res/add_friend_normal.png);
  22. }
  23. #add_btn[state='hover']{
  24. border-image: url(:/res/add_friend_hover.png);
  25. }
  26. #add_btn[state='press']{
  27. border-image: url(:/res/add_friend_hover.png);
  28. }
  29. #receive_btn[state='normal']{
  30. background: #f0f0f0;
  31. color: #2cb46e;
  32. font-size: 16px; /* 设置字体大小 */
  33. font-family: "Microsoft YaHei"; /* 设置字体 */
  34. border-radius: 20px; /* 设置圆角 */
  35. }
  36. #receive_btn[state='hover']{
  37. background: #d2d2d2;
  38. color: #2cb46e;
  39. font-size: 16px; /* 设置字体大小 */
  40. font-family: "Microsoft YaHei"; /* 设置字体 */
  41. border-radius: 20px; /* 设置圆角 */
  42. }
  43. #receive_btn[state='press']{
  44. background: #c6c6c6;
  45. color: #2cb46e;
  46. font-size: 16px; /* 设置字体大小 */
  47. font-family: "Microsoft YaHei"; /* 设置字体 */
  48. border-radius: 20px; /* 设置圆角 */
  49. }
  50. #send_btn[state='normal']{
  51. background: #f0f0f0;
  52. color: #2cb46e;
  53. font-size: 16px; /* 设置字体大小 */
  54. font-family: "Microsoft YaHei"; /* 设置字体 */
  55. border-radius: 20px; /* 设置圆角 */
  56. }
  57. #send_btn[state='hover']{
  58. background: #d2d2d2;
  59. color: #2cb46e;
  60. font-size: 16px; /* 设置字体大小 */
  61. font-family: "Microsoft YaHei"; /* 设置字体 */
  62. border-radius: 20px; /* 设置圆角 */
  63. }
  64. #send_btn[state='press']{
  65. background: #c6c6c6;
  66. color: #2cb46e;
  67. font-size: 16px; /* 设置字体大小 */
  68. font-family: "Microsoft YaHei"; /* 设置字体 */
  69. border-radius: 20px; /* 设置圆角 */
  70. }
  71. #tool_wid{
  72. background: #ffffff;
  73. border-bottom: 0.5px solid #ececec; /* 设置下边框颜色和宽度 */
  74. }
  75. #emo_lb[state='normal']{
  76. border-image: url(:/res/smile.png);
  77. }
  78. #emo_lb[state='hover']{
  79. border-image: url(:/res/smile_hover.png);
  80. }
  81. #emo_lb[state='press']{
  82. border-image: url(:/res/smile_press.png);
  83. }
  84. #file_lb[state='normal']{
  85. border-image: url(:/res/filedir.png);
  86. }
  87. #file_lb[state='hover']{
  88. border-image: url(:/res/filedir_hover.png);
  89. }
  90. #file_lb[state='press']{
  91. border-image: url(:/res/filedir_press.png);
  92. }

效果

最后整体运行一下看看效果, 下一节我们实现红框内的内容

https://cdn.llfc.club/1717645209118.jpg

视频链接

https://www.bilibili.com/video/BV13Z421W7WA/?spm_id_from=333.788&vd_source=8be9e83424c2ed2c9b2a3ed1d01385e9

源码链接

https://gitee.com/secondtonone1/llfcchat

热门评论

热门文章

  1. Qt环境搭建

    喜欢(517) 浏览(24684)
  2. vscode搭建windows C++开发环境

    喜欢(596) 浏览(83344)
  3. 聊天项目(28) 分布式服务通知好友申请

    喜欢(507) 浏览(6093)
  4. 使用hexo搭建个人博客

    喜欢(533) 浏览(11888)
  5. Linux环境搭建和编码

    喜欢(594) 浏览(13540)

最新评论

  1. 堆排序 secondtonone1:堆排序非常实用,定时器就是这个原理制作的。
  2. 创建项目和编译 secondtonone1:谢谢支持
  3. 再谈单例模式 secondtonone1:是的,C++11以后返回局部static变量对象能保证线程安全了。
  4. visual studio配置boost库 一giao里我离giaogiao:请问是修改成这样吗:.\b2.exe toolset=MinGW
  5. 处理网络粘包问题 zyouth: //消息的长度小于头部规定的长度,说明数据未收全,则先将部分消息放到接收节点里 if (bytes_transferred < data_len) { memcpy(_recv_msg_node->_data + _recv_msg_node->_cur_len, _data + copy_len, bytes_transferred); _recv_msg_node->_cur_len += bytes_transferred; ::memset(_data, 0, MAX_LENGTH); _socket.async_read_some(boost::asio::buffer(_data, MAX_LENGTH), std::bind(&CSession::HandleRead, this, std::placeholders::_1, std::placeholders::_2, shared_self)); //头部处理完成 _b_head_parse = true; return; } 把_b_head_parse = true;放在_socket.async_read_some前面是不是更好
  6. 类和对象 陈宇航:支持!!!!
  7. 聊天项目(7) visualstudio配置grpc diablorrr:cmake文件得改一下 find_package(Boost REQUIRED COMPONENTS system filesystem),要加上filesystem。在target_link_libraries中也同样加上
  8. string类 WangQi888888:确实错了,应该是!isspace(sind[index]). 否则不进入循环,还是原来的字符串“some string”
  9. 解决博客回复区被脚本注入的问题 secondtonone1:走到现在我忽然明白一个道理,无论工作也好生活也罢,最重要的是开心,即使一份安稳的工作不能给我带来事业上的积累也要合理的舍弃,所以我还是想去做喜欢的方向。
  10. 利用栅栏实现同步 Dzher:作者你好!我觉得 std::thread a(write_x); std::thread b(write_y); std::thread c(read_x_then_y); std::thread d(read_y_then_x); 这个例子中的assert fail并不会发生,原子变量设定了非relaxed内存序后一个线程的原子变量被写入,那么之后的读取一定会被同步的,c和d线程中只可能同时发生一个z++未执行的情况,最终z不是1就是2了,我测试了很多次都没有assert,请问我这个观点有什么错误,谢谢!
  11. 面试题汇总(一) secondtonone1:看到网络上经常提问的go的问题,做了一下汇总,结合自己的经验给出的答案,如有纰漏,望指正批评。
  12. 聊天项目(15) 客户端实现TCP管理者 lkx:已经在&QTcpSocket::readyRead 回调函数中做了处理了的。
  13. Qt 对话框 Spade2077:QDialog w(); //这里是不是不需要带括号
  14. 答疑汇总(thread,async源码分析) Yagus:如果引用计数为0,则会执行 future 的析构进而等待任务执行完成,那么看到的输出将是 这边应该不对吧,std::future析构只在这三种情况都满足的时候才回block: 1.共享状态是std::async 创造的(类型是_Task_async_state) 2.共享状态没有ready 3.这个future是共享状态的最后一个引用 这边共享状态类型是“_Package_state”,引用计数即使为0也不应该block啊
  15. 构造函数 secondtonone1:构造函数是类的基础知识,要着重掌握
  16. Qt MVC结构之QItemDelegate介绍 胡歌-此生不换:gpt, google
  17. protobuf配置和使用 熊二:你可以把dll放到系统目录,也可以配置环境变量,还能把dll丢到lib里
  18. boost::asio之socket的创建和连接 项空月:发现一些错别字 :每隔vector存储  是不是是每个. asio::mutable_buffers_1 o或者    是不是多打了个o
  19. 无锁并发队列 TenThousandOne:_head  和 _tail  替换为原子变量。那里pop的逻辑,val = _data[h] 可以移到循环外面吗
  20. 聊天项目(9) redis服务搭建 pro_lin:redis线程池的析构函数,除了pop出队列,还要free掉redis连接把
  21. C++ 并发三剑客future, promise和async Yunfei:大佬您好,如果这个线程池中加入的异步任务的形参如果有右值引用,这个commit中的返回类型推导和bind绑定就会出现问题,请问实际工程中,是不是不会用到这种任务,如果用到了,应该怎么解决?
  22. interface应用 secondtonone1:interface是万能类型,但是使用时要转换为实际类型来使用。interface丰富了go的多态特性,也降低了传统面向对象语言的耦合性。
  23. 网络编程学习方法和图书推荐 Corleone:啥程度可以找工作

个人公众号

个人微信