#include "historymessagewidget.h" //工厂函数 HistoryItem* HistoryItem::makeHistoryItem(const Message& message) { // 1. 创建出对象 HistoryItem* item = new HistoryItem(); item->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Preferred); // 2. 创建布局 QGridLayout* layout = new QGridLayout(); layout->setVerticalSpacing(0); layout->setHorizontalSpacing(10); layout->setContentsMargins(0, 0, 0, 0); item->setLayout(layout); // 3. 创建头像 QPushButton* avatarBtn = new QPushButton(); avatarBtn->setFixedSize(40, 40); avatarBtn->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed); avatarBtn->setIconSize(QSize(40, 40)); // 当前消息发送者的头像 avatarBtn->setIcon(message.sender.avatar); avatarBtn->setStyleSheet("QPushButton { border: none; }"); // 4. 创建昵称和时间 QLabel* nameLabel = new QLabel(); nameLabel->setText(message.sender.nickname + " | " + message.time); nameLabel->setFixedHeight(20); // 高度设置为头像高度的一半 nameLabel->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed); // 5. 消息内容部分 QWidget* contentWidget = nullptr; if (message.messageType == model::MessageType::TEXT_TYPE) { // 文本消息 QLabel* label = new QLabel(); label->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding); label->setWordWrap(true); label->setText(QString(message.content)); label->adjustSize(); // 设置让 label 能够自动调整大小 contentWidget = label; } else if (message.messageType == model::MessageType::IMAGE_TYPE) { // 图片消息 //contentWidget = new ImageButton(message.fileId, message.content); } else if (message.messageType == model::MessageType::FILE_TYPE) { // 文件消息 //contentWidget = new FileLabel(message.fileId, message.fileName); } else if (message.messageType == model::MessageType::SPEECH_TYPE) { // 语音消息 //contentWidget = new SpeechLabel(message.fileId); } else { LOG() << "错误的消息类型! messageType=" << message.messageType; } // 6. 把上述控件添加到布局中 layout->addWidget(avatarBtn, 0, 0, 2, 1); layout->addWidget(nameLabel, 0, 1, 1, 1); layout->addWidget(contentWidget, 1, 1, 5, 1); return item; } HistoryMessageWidget::HistoryMessageWidget(QWidget *parent) : QDialog(parent) { // 1. 设置窗口本身属性 this->setFixedSize(600, 600); this->setWindowTitle("历史消息"); this->setWindowIcon(QIcon(":/resource/image/logo.png")); this->setStyleSheet("QWidget { background-color: rgb(255, 255, 255); }"); this->setAttribute(Qt::WA_DeleteOnClose); // 2. 创建布局管理器. QGridLayout* layout = new QGridLayout(); layout->setSpacing(10); layout->setContentsMargins(30, 30, 30, 0); this->setLayout(layout); // 3. 创建单选按钮 keyRadioBtn = new QRadioButton(); timeRadioBtn = new QRadioButton(); keyRadioBtn->setText("按关键词查询"); timeRadioBtn->setText("按时间查询"); // 默认按照关键词查询 keyRadioBtn->setChecked(true); layout->addWidget(keyRadioBtn, 0, 0, 1, 2); layout->addWidget(timeRadioBtn, 0, 2, 1, 2); // 4. 创建搜索框 searchEdit = new QLineEdit(); searchEdit->setFixedHeight(50); searchEdit->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed); searchEdit->setPlaceholderText("要搜索的关键词"); searchEdit->setStyleSheet("QLineEdit { border: none; border-radius: 10px; color: rgb(129, 129, 129); background-color: rgb(240, 240, 240); font-size: 16px; padding-left: 10px; }"); layout->addWidget(searchEdit, 1, 0, 1, 8); // 5. 创建搜索按钮 QPushButton* searchBtn = new QPushButton(); searchBtn->setFixedSize(50, 50); searchBtn->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed); searchBtn->setIconSize(QSize(30, 30)); searchBtn->setIcon(QIcon(":/resource/image/search.png")); QString btnStyle = "QPushButton { border: none; background-color: rgb(240, 240, 240); border-radius: 10px; }"; btnStyle += "QPushButton:pressed { background-color: rgb(220, 220, 220); }"; searchBtn->setStyleSheet(btnStyle); layout->addWidget(searchBtn, 1, 8, 1, 1); // 6. 创建时间相关的部分控件, 初始情况下要隐藏 QLabel* begTag = new QLabel(); begTag->setText("开始时间"); QLabel* endTag = new QLabel(); endTag->setText("结束时间"); begTimeEdit = new QDateTimeEdit(); endTimeEdit = new QDateTimeEdit(); begTimeEdit->setStyleSheet("QDateTimeEdit { color: rgb(0, 0, 0); } "); endTimeEdit->setStyleSheet("QDateTimeEdit { color: rgb(0, 0, 0); } "); // [联调新增] begTimeEdit->setDisplayFormat("yyyy-MM-dd hh:mm"); endTimeEdit->setDisplayFormat("yyyy-MM-dd hh:mm"); begTimeEdit->setFixedHeight(40); endTimeEdit->setFixedHeight(40); begTag->hide(); endTag->hide(); begTimeEdit->hide(); endTimeEdit->hide(); // 7. 创建滚动区域 initScrollArea(layout); // 8. 设置槽函数 connect(keyRadioBtn, &QRadioButton::clicked, this, [=]() { // 把时间相关的控件, 隐藏起来 layout->removeWidget(begTag); layout->removeWidget(begTimeEdit); layout->removeWidget(endTag); layout->removeWidget(endTimeEdit); begTag->hide(); begTimeEdit->hide(); endTag->hide(); endTimeEdit->hide(); // 把关键词搜索框显示加入布局 layout->addWidget(searchEdit, 1, 0, 1, 8); searchEdit->show(); }); connect(timeRadioBtn, &QRadioButton::clicked, this, [=]() { // 关键词搜索框隐藏并从布局中删除掉. layout->removeWidget(searchEdit); searchEdit->hide(); // 把时间相关的控件, 添加到布局中, 并且进行显示. layout->addWidget(begTag, 1, 0, 1, 1); layout->addWidget(begTimeEdit, 1, 1, 1, 3); layout->addWidget(endTag, 1, 4, 1, 1); layout->addWidget(endTimeEdit, 1, 5, 1, 3); begTag->show(); begTimeEdit->show(); endTag->show(); endTimeEdit->show(); }); //connect(searchBtn, &QPushButton::clicked, this, &HistoryMessageWidget::clickSearchBtn); // 构造测试数据 #if TEST_UI for (int i = 0; i < 30; ++i) { // 注意此处代码和前面的差别. // 前面有个代码, UserInfo 必须要 new 出来才能构造. 当时 Item 对象里, 持有了 const UserInfo& , 不是 new 的话 // 就可能使引用指向的对象失效的. // 此处后续的代码, 都是按照传值的方式来使用 message 的内容, 不 new 也行. model::UserInfo sender; sender.userId = ""; sender.nickname = "张三" + QString::number(i); sender.avatar = QIcon(":/resource/image/defaultAvatar.png"); sender.description = ""; sender.phone = "18612345678"; Message message = Message::makeMessage(model::MessageType::TEXT_TYPE, "", sender, QString("消息内容" + QString::number(i)).toUtf8(), ""); this->addHistoryMessage(message); } #endif } void HistoryMessageWidget::addHistoryMessage(const Message& message) { HistoryItem* item = HistoryItem::makeHistoryItem(message); container->layout()->addWidget(item); } void HistoryMessageWidget::clear() { QVBoxLayout* layout = dynamic_cast(container->layout()); for (int i = layout->count() - 1; i >= 0; i--) { //之前使用的是takeat,效果和这个是一样的, QWidget* w = layout->itemAt(i)->widget(); if (w == nullptr) { continue; } layout->removeWidget(w); w->deleteLater(); } } void HistoryMessageWidget::initScrollArea(QGridLayout* layout) { // 1. 创建滚动区域对象 QScrollArea* scrollArea = new QScrollArea(); scrollArea->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding); scrollArea->setWidgetResizable(true); scrollArea->verticalScrollBar()->setStyleSheet("QScrollBar:vertical { width: 2px; background-color: rgb(255, 255, 255); }"); scrollArea->horizontalScrollBar()->setStyleSheet("QScrollBar:horizontal { height: 0; }"); scrollArea->setStyleSheet("QScrollArea { border: none; }"); // 2. 创建 QWidget, 持有要加入的新的内容 container = new QWidget(); scrollArea->setWidget(container); // 3. 创建 container 中的布局管理器. QVBoxLayout* vlayout = new QVBoxLayout(); vlayout->setSpacing(10); vlayout->setContentsMargins(0, 0, 0, 0); vlayout->setAlignment(Qt::AlignTop); container->setLayout(vlayout); // 4. 把滚动区加入到整个 layout 中 layout->addWidget(scrollArea, 2, 0, 1, 9); }