聊天项目(19) 实现搜索框和聊天列表

搜索框

我们需要实现如下效果

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

输入框默认不显示关闭按钮,当输入文字后显示关闭按钮,点击关闭按钮清空文字

添加CustomizeEdit类,头文件

  1. #ifndef CUSTOMIZEEDIT_H
  2. #define CUSTOMIZEEDIT_H
  3. #include <QLineEdit>
  4. #include <QDebug>
  5. class CustomizeEdit: public QLineEdit
  6. {
  7. Q_OBJECT
  8. public:
  9. CustomizeEdit(QWidget *parent = nullptr);
  10. void SetMaxLength(int maxLen);
  11. protected:
  12. void focusOutEvent(QFocusEvent *event) override
  13. {
  14. // 执行失去焦点时的处理逻辑
  15. //qDebug() << "CustomizeEdit focusout";
  16. // 调用基类的focusOutEvent()方法,保证基类的行为得到执行
  17. QLineEdit::focusOutEvent(event);
  18. //发送失去焦点得信号
  19. emit sig_foucus_out();
  20. }
  21. private:
  22. void limitTextLength(QString text) {
  23. if(_max_len <= 0){
  24. return;
  25. }
  26. QByteArray byteArray = text.toUtf8();
  27. if (byteArray.size() > _max_len) {
  28. byteArray = byteArray.left(_max_len);
  29. this->setText(QString::fromUtf8(byteArray));
  30. }
  31. }
  32. int _max_len;
  33. signals:
  34. void sig_foucus_out();
  35. };
  36. #endif // CUSTOMIZEEDIT_H

源文件

  1. #include "customizeedit.h"
  2. CustomizeEdit::CustomizeEdit(QWidget *parent):QLineEdit (parent),_max_len(0)
  3. {
  4. connect(this, &QLineEdit::textChanged, this, &CustomizeEdit::limitTextLength);
  5. }
  6. void CustomizeEdit::SetMaxLength(int maxLen)
  7. {
  8. _max_len = maxLen;
  9. }

设计师界面类里将ui->search_edit提升为CustomizeEdit

在ChatDialog的构造函数中设置输入的长度限制以及关闭等图标的配置

  1. QAction *searchAction = new QAction(ui->search_edit);
  2. searchAction->setIcon(QIcon(":/res/search.png"));
  3. ui->search_edit->addAction(searchAction,QLineEdit::LeadingPosition);
  4. ui->search_edit->setPlaceholderText(QStringLiteral("搜索"));
  5. // 创建一个清除动作并设置图标
  6. QAction *clearAction = new QAction(ui->search_edit);
  7. clearAction->setIcon(QIcon(":/res/close_transparent.png"));
  8. // 初始时不显示清除图标
  9. // 将清除动作添加到LineEdit的末尾位置
  10. ui->search_edit->addAction(clearAction, QLineEdit::TrailingPosition);
  11. // 当需要显示清除图标时,更改为实际的清除图标
  12. connect(ui->search_edit, &QLineEdit::textChanged, [clearAction](const QString &text) {
  13. if (!text.isEmpty()) {
  14. clearAction->setIcon(QIcon(":/res/close_search.png"));
  15. } else {
  16. clearAction->setIcon(QIcon(":/res/close_transparent.png")); // 文本为空时,切换回透明图标
  17. }
  18. });
  19. // 连接清除动作的触发信号到槽函数,用于清除文本
  20. connect(clearAction, &QAction::triggered, [this, clearAction]() {
  21. ui->search_edit->clear();
  22. clearAction->setIcon(QIcon(":/res/close_transparent.png")); // 清除文本后,切换回透明图标
  23. ui->search_edit->clearFocus();
  24. //清除按钮被按下则不显示搜索框
  25. //ShowSearch(false);
  26. });
  27. ui->search_edit->SetMaxLength(15);

stylesheet.qss 中修改样式

  1. #search_wid{
  2. background-color:rgb(247,247,247);
  3. }
  4. #search_edit {
  5. border: 2px solid #f1f1f1;
  6. }

聊天记录列表

创建C++ 类ChatUserList

  1. #ifndef CHATUSERLIST_H
  2. #define CHATUSERLIST_H
  3. #include <QListWidget>
  4. #include <QWheelEvent>
  5. #include <QEvent>
  6. #include <QScrollBar>
  7. #include <QDebug>
  8. class ChatUserList: public QListWidget
  9. {
  10. Q_OBJECT
  11. public:
  12. ChatUserList(QWidget *parent = nullptr);
  13. protected:
  14. bool eventFilter(QObject *watched, QEvent *event) override;
  15. signals:
  16. void sig_loading_chat_user();
  17. };
  18. #endif // CHATUSERLIST_H

实现

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

在设计师界面类里提升ui->chat_user_list为ChatUserList

在ChatDialog构造函数和搜索清除按钮的回调中增加

  1. ShowSearch(false);

该函数的具体实现

  1. void ChatDialog::ShowSearch(bool bsearch)
  2. {
  3. if(bsearch){
  4. ui->chat_user_list->hide();
  5. ui->con_user_list->hide();
  6. ui->search_list->show();
  7. _mode = ChatUIMode::SearchMode;
  8. }else if(_state == ChatUIMode::ChatMode){
  9. ui->chat_user_list->show();
  10. ui->con_user_list->hide();
  11. ui->search_list->hide();
  12. _mode = ChatUIMode::ChatMode;
  13. }else if(_state == ChatUIMode::ContactMode){
  14. ui->chat_user_list->hide();
  15. ui->search_list->hide();
  16. ui->con_user_list->show();
  17. _mode = ChatUIMode::ContactMode;
  18. }
  19. }

ChatDialog类中声明添加

  1. ChatUIMode _mode;
  2. ChatUIMode _state;
  3. bool _b_loading;

构造函数的初始化列表初始化这些模式和状态

  1. ChatDialog::ChatDialog(QWidget *parent) :
  2. QDialog(parent),
  3. ui(new Ui::ChatDialog),_mode(ChatUIMode::ChatMode),
  4. _state(ChatUIMode::ChatMode),_b_loading(false){//...}

为了让用户聊天列表更美观,修改qss文件

  1. #chat_user_wid{
  2. background-color:rgb(0,0,0);
  3. }
  4. #chat_user_list {
  5. background-color: rgb(247,247,248);
  6. border: none;
  7. }
  8. #chat_user_list::item:selected {
  9. background-color: #d3d7d4;
  10. border: none;
  11. outline: none;
  12. }
  13. #chat_user_list::item:hover {
  14. background-color: rgb(206,207,208);
  15. border: none;
  16. outline: none;
  17. }
  18. #chat_user_list::focus {
  19. border: none;
  20. outline: none;
  21. }

添加聊天item

我们要为聊天列表添加item,每个item包含的样式为

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

对于这样的列表元素,我们采用设计师界面类设计非常方便, 新建设计师界面类ChatUserWid, 在ChatUserWid.ui中拖动布局如下

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

我们定义一个基类ListItemBase

  1. #ifndef LISTITEMBASE_H
  2. #define LISTITEMBASE_H
  3. #include <QWidget>
  4. #include "global.h"
  5. class ListItemBase : public QWidget
  6. {
  7. Q_OBJECT
  8. public:
  9. explicit ListItemBase(QWidget *parent = nullptr);
  10. void SetItemType(ListItemType itemType);
  11. ListItemType GetItemType();
  12. private:
  13. ListItemType _itemType;
  14. public slots:
  15. signals:
  16. };
  17. #endif // LISTITEMBASE_H

我们实现这个基类

  1. #include "listitembase.h"
  2. ListItemBase::ListItemBase(QWidget *parent) : QWidget(parent)
  3. {
  4. }
  5. void ListItemBase::SetItemType(ListItemType itemType)
  6. {
  7. _itemType = itemType;
  8. }
  9. ListItemType ListItemBase::GetItemType()
  10. {
  11. return _itemType;
  12. }

我们实现ChatUserWid

  1. #ifndef CHATUSERWID_H
  2. #define CHATUSERWID_H
  3. #include <QWidget>
  4. #include "listitembase.h"
  5. namespace Ui {
  6. class ChatUserWid;
  7. }
  8. class ChatUserWid : public ListItemBase
  9. {
  10. Q_OBJECT
  11. public:
  12. explicit ChatUserWid(QWidget *parent = nullptr);
  13. ~ChatUserWid();
  14. QSize sizeHint() const override {
  15. return QSize(250, 70); // 返回自定义的尺寸
  16. }
  17. void SetInfo(QString name, QString head, QString msg);
  18. private:
  19. Ui::ChatUserWid *ui;
  20. QString _name;
  21. QString _head;
  22. QString _msg;
  23. };
  24. #endif // CHATUSERWID_H

具体实现

  1. #include "chatuserwid.h"
  2. #include "ui_chatuserwid.h"
  3. ChatUserWid::ChatUserWid(QWidget *parent) :
  4. ListItemBase(parent),
  5. ui(new Ui::ChatUserWid)
  6. {
  7. ui->setupUi(this);
  8. SetItemType(ListItemType::CHAT_USER_ITEM);
  9. }
  10. ChatUserWid::~ChatUserWid()
  11. {
  12. delete ui;
  13. }
  14. void ChatUserWid::SetInfo(QString name, QString head, QString msg)
  15. {
  16. _name = name;
  17. _head = head;
  18. _msg = msg;
  19. // 加载图片
  20. QPixmap pixmap(_head);
  21. // 设置图片自动缩放
  22. ui->icon_lb->setPixmap(pixmap.scaled(ui->icon_lb->size(), Qt::KeepAspectRatio, Qt::SmoothTransformation));
  23. ui->icon_lb->setScaledContents(true);
  24. ui->user_name_lb->setText(_name);
  25. ui->user_chat_lb->setText(_msg);
  26. }

在ChatDialog里定义一些全局的变量用来做测试

  1. std::vector<QString> strs ={"hello world !",
  2. "nice to meet u",
  3. "New year,new life",
  4. "You have to love yourself",
  5. "My love is written in the wind ever since the whole world is you"};
  6. std::vector<QString> heads = {
  7. ":/res/head_1.jpg",
  8. ":/res/head_2.jpg",
  9. ":/res/head_3.jpg",
  10. ":/res/head_4.jpg",
  11. ":/res/head_5.jpg"
  12. };
  13. std::vector<QString> names = {
  14. "llfc",
  15. "zack",
  16. "golang",
  17. "cpp",
  18. "java",
  19. "nodejs",
  20. "python",
  21. "rust"
  22. };

这些数据只是测试数据,实际数据是后端传输过来的,我们目前只测试界面功能,用测试数据即可,写一个函数根据上面的数据添加13条item记录

  1. void ChatDialog::addChatUserList()
  2. {
  3. // 创建QListWidgetItem,并设置自定义的widget
  4. for(int i = 0; i < 13; i++){
  5. int randomValue = QRandomGenerator::global()->bounded(100); // 生成0到99之间的随机整数
  6. int str_i = randomValue%strs.size();
  7. int head_i = randomValue%heads.size();
  8. int name_i = randomValue%names.size();
  9. auto *chat_user_wid = new ChatUserWid();
  10. chat_user_wid->SetInfo(names[name_i], heads[head_i], strs[str_i]);
  11. QListWidgetItem *item = new QListWidgetItem;
  12. //qDebug()<<"chat_user_wid sizeHint is " << chat_user_wid->sizeHint();
  13. item->setSizeHint(chat_user_wid->sizeHint());
  14. ui->chat_user_list->addItem(item);
  15. ui->chat_user_list->setItemWidget(item, chat_user_wid);
  16. }
  17. }

在ChatDialog构造函数中添加

  1. addChatUserList();

完善界面效果,新增qss

  1. ChatUserWid {
  2. background-color:rgb(247,247,247);
  3. border: none;
  4. }
  5. #user_chat_lb{
  6. color:rgb(153,153,153);
  7. font-size: 12px;
  8. font-family: "Microsoft YaHei";
  9. }
  10. #user_name_lb{
  11. color:rgb(0,0,0);
  12. font-size: 14px;
  13. font-weight: normal;
  14. font-family: "Microsoft YaHei";
  15. }
  16. #time_wid #time_lb{
  17. color:rgb(140,140,140);
  18. font-size: 12px;
  19. font-family: "Microsoft YaHei";
  20. }
  21. QScrollBar:vertical {
  22. background: transparent; /* 将轨道背景设置为透明 */
  23. width: 8px; /* 滚动条宽度,根据需要调整 */
  24. margin: 0px; /* 移除滚动条与滑块之间的间距 */
  25. }
  26. QScrollBar::handle:vertical {
  27. background: rgb(173,170,169); /* 滑块颜色 */
  28. min-height: 10px; /* 滑块最小高度,根据需要调整 */
  29. border-radius: 4px; /* 滑块边缘圆角,调整以形成椭圆形状 */
  30. }
  31. QScrollBar::add-line:vertical, QScrollBar::sub-line:vertical {
  32. height: 0px; /* 移除上下按钮 */
  33. border: none; /* 移除边框 */
  34. background: transparent; /* 背景透明 */
  35. }
  36. QScrollBar::add-page:vertical, QScrollBar::sub-page:vertical {
  37. background: none; /* 页面滚动部分背景透明 */
  38. }

测试效果

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

源码链接

https://gitee.com/secondtonone1/llfcchat

视频链接

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

热门评论

热门文章

  1. 解密定时器的实现细节

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

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

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

    喜欢(587) 浏览(1801)
  5. slice介绍和使用

    喜欢(521) 浏览(1880)

最新评论

  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. 类和对象 陈宇航:支持!!!!

个人公众号

个人微信