From beda1e32ad498c99893476c3adafb1ee34a9bfa5 Mon Sep 17 00:00:00 2001 From: xyz <2050965275@qq.com> Date: Mon, 26 May 2025 20:00:33 +0800 Subject: [PATCH] update showMessage --- mainwidget.cpp | 10 +-- messageshowarea.cpp | 197 ++++++++++++++++++++++++++++++++++++++++-- messageshowarea.h | 32 +++++++ sessionfriendarea.cpp | 16 ++-- 4 files changed, 237 insertions(+), 18 deletions(-) diff --git a/mainwidget.cpp b/mainwidget.cpp index 1979681..e9340d7 100644 --- a/mainwidget.cpp +++ b/mainwidget.cpp @@ -61,12 +61,12 @@ void MainWidget::initMainWindow() windowLeft->setFixedWidth(70); - windowMid->setFixedWidth(820); + windowMid->setFixedWidth(320); windowRight->setMinimumWidth(900); windowLeft->setStyleSheet("QWidget { background-color: rgb(46, 46, 46); }"); windowMid->setStyleSheet("QWidget { background-color: rgb(247, 247, 247); }"); - windowRight->setStyleSheet("QWidget { background-color: rgb(225, 225, 225); }"); + windowRight->setStyleSheet("QWidget { background-color: rgb(245, 245, 245); }"); layout->addWidget(windowLeft); layout->addWidget(windowMid); @@ -157,7 +157,7 @@ void MainWidget::initMidWindow() layout->addWidget(addFriendBtn, 0 ,3); layout->addWidget(spacer3, 0, 4); - layout->addWidget(spacer4, 1, 0); + layout->addWidget(spacer4, 1, 0, 1, 5); layout->addWidget(sessionFriendArea, 2, 0, 1, 5); } @@ -175,8 +175,8 @@ void MainWidget::initRightWindow() titleWidget->setFixedHeight(62); titleWidget->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed); titleWidget->setObjectName("titleWidget"); - titleWidget->setStyleSheet(R"(#titleWidget { border-bottom: 1px solid rgb(230, 230, 230); - border-left: 1px solid rgb(230, 230, 230); } + titleWidget->setStyleSheet(R"(#titleWidget { border-bottom: 2px solid rgb(231, 231, 231); + border-left: 1px solid rgb(231, 231, 231); } )"); vlayout->addWidget(titleWidget); diff --git a/messageshowarea.cpp b/messageshowarea.cpp index ce06939..0d3b15f 100644 --- a/messageshowarea.cpp +++ b/messageshowarea.cpp @@ -19,6 +19,55 @@ MessageShowArea::MessageShowArea() { layout->setSpacing(0); layout->setContentsMargins(0, 0, 0, 0); container->setLayout(layout); + + // 添加测试数据 +#if TEST_UI + bool k = true; + for(int i = 0; i < 30; i++) { + model::UserInfo userInfo; + userInfo.nickname = "xyz" + QString::number(i); + userInfo.avatar = QIcon(":/resource/image/defaultAvatar.png"); + Message message = Message::makeMessage(model::TEXT_TYPE, "", userInfo, (QString("this is a test message...") + QString::number(i)).toUtf8(), ""); + k = !k; + this->addMessage(k, message); + } + + //测试长消息 + model::UserInfo userInfo; + userInfo.nickname = "???"; + + const QString s = R"(The starry sky is just a few years ago. And the past may no longer exist,The only thing that remains is light years away, it's just an ethereal phantom.)"; + + userInfo.avatar = QIcon(":/resource/image/defaultAvatar.png"); + Message message = Message::makeMessage(model::TEXT_TYPE, "", userInfo, s.toUtf8(), ""); + this->addMessage(false, message); +#endif + +} + +void MessageShowArea::addFrontMessage(bool isLeft, const Message &message) +{ + MessageItem* messageItem = MessageItem::makeMessageItem(isLeft, message); + QVBoxLayout* layout = dynamic_cast(container->layout()); + layout->insertWidget(0, messageItem); +} + +void MessageShowArea::addMessage(bool isLeft, const Message &message) +{ + MessageItem* messageItem = MessageItem::makeMessageItem(isLeft, message); + container->layout()->addWidget(messageItem); +} + +void MessageShowArea::clear() +{ + QLayout* layout = container->layout(); + //要遍历布局管理器,删除里面的元素 + for(int i = layout->count() - 1; i >= 0; i--) { + QLayoutItem* item = layout->takeAt(i); + if(item != nullptr && item->widget() != nullptr) { + delete item->widget(); + } + } } //////////////////////////////////////////// @@ -35,8 +84,8 @@ MessageItem *MessageItem::makeMessageItem(bool isLeft, const Message &message) //创建对象和布局管理器 MessageItem* messageItem = new MessageItem(isLeft); QGridLayout* layout = new QGridLayout(); - layout->setSpacing(0); - layout->setContentsMargins(0, 0, 0, 0); + layout->setSpacing(10); + layout->setContentsMargins(30, 10, 40, 0); //这个message最低不能低于100 messageItem->setMinimumHeight(100); @@ -48,9 +97,9 @@ MessageItem *MessageItem::makeMessageItem(bool isLeft, const Message &message) avatarBtn->setIconSize(QSize(40, 40)); avatarBtn->setIcon(message.sender.avatar); if(isLeft) { - layout->addWidget(avatarBtn, 0, 0, 2, 1, Qt::AlignTop | Qt::AlignLeft); + layout->addWidget(avatarBtn, 0, 0, 2, 1, Qt::AlignCenter | Qt::AlignLeft); } else { - layout->addWidget(avatarBtn, 0, 1, 2, 1, Qt::AlignTop | Qt::AlignRight); + layout->addWidget(avatarBtn, 0, 1, 2, 1, Qt::AlignCenter | Qt::AlignRight); } //创建名字和时间 @@ -65,7 +114,145 @@ MessageItem *MessageItem::makeMessageItem(bool isLeft, const Message &message) } //创建消息体 - + QWidget* contentWidget = nullptr; + switch(message.messageType) { + case model::TEXT_TYPE: + contentWidget = makeTextMessageItem(isLeft, message.content); + break; + case model::IMAGE_TYPE: + contentWidget = makeImageMessageItem(); + break; + case model::FILE_TYPE: + contentWidget = makeFileMessageItem(); + break; + case model::SPEECH_TYPE: + contentWidget = makeSpeechMessageItem(); + break; + default: + LOG() << "error messageType: " << message.messageType; + } + if(isLeft) { + layout->addWidget(contentWidget, 1, 1); + } else { + layout->addWidget(contentWidget, 1, 0); + } return messageItem; } + +QWidget *MessageItem::makeTextMessageItem(bool isLeft, const QString &text) +{ + MessageContentLabel* messageContentLabel = new MessageContentLabel(text, isLeft); + return messageContentLabel; +} + +QWidget *MessageItem::makeImageMessageItem() +{ + return nullptr; +} + +QWidget *MessageItem::makeFileMessageItem() +{ + return nullptr; +} + +QWidget *MessageItem::makeSpeechMessageItem() +{ + return nullptr; +} + + + +//////////////////////////////////////////// +/// 创建类表示“文本消息”正文部分 +//////////////////////////////////////////// +MessageContentLabel::MessageContentLabel(const QString &text, bool isLeft) + :isLeft(isLeft) +{ + this->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding); + + QFont font; + font.setFamily("微软雅黑"); + font.setPixelSize(16); + + this->label = new QLabel(this); + this->label->setText(text); + this->label->setFont(font); + this->label->setAlignment(Qt::AlignCenter | Qt::AlignLeft); + this->label->setWordWrap(true); + this->label->setStyleSheet("QLabel { padding: 0 10px; line-height: 1.2; background-color: transparent; }"); +} + +//这个函数会在该控件被显示时,自动的调用到 +void MessageContentLabel::paintEvent(QPaintEvent *event) +{ + (void) event; + + //获取到父元素的宽度 + QObject* object = this->parent(); + if(!object->isWidgetType()) { + //说明当前的对象不是QWidget,则不需要进行任何后续的绘制操作 + return; + } + QWidget* parent = dynamic_cast(object); + int width = parent->width() * 0.6; + + //计算当前文本,如果单行防止放置需要多宽 + QFontMetrics metrics(this->label->font()); + int totalWidth = metrics.horizontalAdvance(this->label->text()); + + //计算出此处的行数是多少 + int rows = (totalWidth / (width - 40)) + 1; + if(rows == 1) { + //若此时得到的行数只有一行 + width = totalWidth + 40; + } + + //根据行数来确定高度 + //行数 × 行高(字体高度的 1.2 倍) + 上下内边距(各 10px) + int height = rows * (this->label->font().pixelSize() * 1.2 ) + 20; + + //绘制圆角矩形和箭头 + QPainter painter(this); + QPainterPath path; + //设置抗锯齿 + painter.setRenderHint(QPainter::Antialiasing); + if(isLeft) { + painter.setPen(QPen(QColor(255, 255, 255))); + painter.setBrush(QColor(255, 255, 255)); //白色填充 + + //绘制圆角矩形 + painter.drawRoundedRect(10, 0, width, height, 10 ,10); + //绘制箭头 + path.moveTo(10, 15); + path.lineTo(0, 20); + path.lineTo(10, 25); + path.closeSubpath(); //绘制的线形成闭合的多边形,才能进行使用Brush填充颜色 + painter.drawPath(path);//设置好,调用画笔进行绘制操作 + + this->label->setGeometry(10, 0, width, height); + } else { + painter.setPen(QPen(QColor(137, 217, 97))); + painter.setBrush(QColor(137, 217, 97)); + + //圆角矩形左侧边的横坐标位置 + int leftPos = this->width() - width - 10; //10 用来容纳箭头的宽度 + //圆角矩形右侧边的横坐标位置 + int rightPos = this->width() - 10; + + //绘制圆角矩形 + painter.drawRoundedRect(leftPos, 0, width, height, 10, 10); + //绘制箭头 + path.moveTo(rightPos, 15); + path.lineTo(rightPos + 10, 20); + path.lineTo(rightPos, 25); + path.closeSubpath(); //绘制的线形成闭合的多边形,才能进行使用Brush填充颜色 + painter.drawPath(path);//设置好,调用画笔进行绘制操作 + + this->label->setGeometry(leftPos, 0, width, height); + } + + //重新设置父元素的高度,保证父元素足够的高,能够容纳下上述绘制消息的显示区域 + //注意高度要涵盖之前的名字和时间的label的高度,以及留一点的冗余的空间 + parent->setFixedHeight(height + 50); +} diff --git a/messageshowarea.h b/messageshowarea.h index 81d1e94..2f19d8c 100644 --- a/messageshowarea.h +++ b/messageshowarea.h @@ -7,8 +7,12 @@ #include #include #include +#include +#include +#include #include "model/data.h" +#include "debug.h" //.h文件中,不宜使用namespace xxx using model::Message; @@ -22,6 +26,14 @@ class MessageShowArea : public QScrollArea public: MessageShowArea(); + //头插 + void addFrontMessage(bool isLeft, const Message& message); + //尾插 + void addMessage(bool isLeft, const Message& message); + + //清空 + void clear(); + private: QWidget* container; }; @@ -38,8 +50,28 @@ public: //通过工厂方法创建MessageItem实例 static MessageItem* makeMessageItem(bool isLeft, const Message& message); + //添加工厂函数 + static QWidget* makeTextMessageItem(bool isLeft, const QString& message); + static QWidget* makeImageMessageItem(); + static QWidget* makeFileMessageItem(); + static QWidget* makeSpeechMessageItem(); + private: bool isLeft; }; +//////////////////////////////////////////// +/// 创建类表示“文本消息”正文部分 +//////////////////////////////////////////// +class MessageContentLabel : public QWidget { +public: + MessageContentLabel(const QString& text, bool isLeft); + + void paintEvent(QPaintEvent* event) override; + +private: + QLabel* label; + bool isLeft; +}; + #endif // MESSAGESHOWAREA_H diff --git a/sessionfriendarea.cpp b/sessionfriendarea.cpp index fdb98c5..5f5e60d 100644 --- a/sessionfriendarea.cpp +++ b/sessionfriendarea.cpp @@ -17,7 +17,7 @@ SessionFriendArea::SessionFriendArea(QWidget *parent) this->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff); this->verticalScrollBar()->setStyleSheet(R"( QScrollBar:vertical { - background-color: rgb(231, 231, 231); /* 滚动条背景透明 */ + background-color: rgb(228, 228, 228); /* 滚动条背景透明 */ width: 6px; /* 默认宽度 */ margin: 0px 0px 0px 0px; /* 边距清零 */ } @@ -84,7 +84,7 @@ SessionFriendItem::SessionFriendItem(QWidget* owner, const QIcon& avatar, const { this->setFixedHeight(70); - this->setStyleSheet("QWidget { background-color: rgb(231, 231, 231); }"); + this->setStyleSheet("QWidget { background-color: rgb(228, 228, 228); }"); //创建网格布局管理器 @@ -122,8 +122,8 @@ SessionFriendItem::SessionFriendItem(QWidget* owner, const QIcon& avatar, const //添加到网格布局 layout->addWidget(avatarBtn, 0, 0, 2, 2); - layout->addWidget(nameLabel, 0, 2, 1, 8); - layout->addWidget(messageLabel, 1, 2, 1, 8); + layout->addWidget(nameLabel, 0, 2, 1, 25); + layout->addWidget(messageLabel, 1, 2, 1, 25); } void SessionFriendItem::paintEvent(QPaintEvent *event) @@ -150,7 +150,7 @@ void SessionFriendItem::enterEvent(QEvent *event) return; } - this->setStyleSheet("QWidget { background-color: rgb(220, 220, 220); }"); + this->setStyleSheet("QWidget { background-color: rgb(215, 215, 215); }"); } void SessionFriendItem::leaveEvent(QEvent *event) @@ -161,7 +161,7 @@ void SessionFriendItem::leaveEvent(QEvent *event) return; } - this->setStyleSheet("QWidget { background-color: rgb(231, 231, 231); }"); + this->setStyleSheet("QWidget { background-color: rgb(228, 228, 228); }"); } void SessionFriendItem::select() @@ -176,12 +176,12 @@ void SessionFriendItem::select() SessionFriendItem* item = dynamic_cast(child); if(item->selected) { item->selected = false; - item->setStyleSheet("QWidget { background-color: rgb(231, 231, 231); }"); + item->setStyleSheet("QWidget { background-color: rgb(228, 228, 228); }"); } } //鼠标点击时会触发这个事件 //点击时修改背景色 - this->setStyleSheet("QWidget { background-color: rgb(210, 210, 210); }"); + this->setStyleSheet("QWidget { background-color: rgb(196, 196, 196); }"); this->selected = true; //调用Active