update showMessage

This commit is contained in:
xyz
2025-05-26 20:00:33 +08:00
parent 4dcec01d67
commit beda1e32ad
4 changed files with 237 additions and 18 deletions

View File

@ -61,12 +61,12 @@ void MainWidget::initMainWindow()
windowLeft->setFixedWidth(70); windowLeft->setFixedWidth(70);
windowMid->setFixedWidth(820); windowMid->setFixedWidth(320);
windowRight->setMinimumWidth(900); windowRight->setMinimumWidth(900);
windowLeft->setStyleSheet("QWidget { background-color: rgb(46, 46, 46); }"); windowLeft->setStyleSheet("QWidget { background-color: rgb(46, 46, 46); }");
windowMid->setStyleSheet("QWidget { background-color: rgb(247, 247, 247); }"); 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(windowLeft);
layout->addWidget(windowMid); layout->addWidget(windowMid);
@ -157,7 +157,7 @@ void MainWidget::initMidWindow()
layout->addWidget(addFriendBtn, 0 ,3); layout->addWidget(addFriendBtn, 0 ,3);
layout->addWidget(spacer3, 0, 4); layout->addWidget(spacer3, 0, 4);
layout->addWidget(spacer4, 1, 0); layout->addWidget(spacer4, 1, 0, 1, 5);
layout->addWidget(sessionFriendArea, 2, 0, 1, 5); layout->addWidget(sessionFriendArea, 2, 0, 1, 5);
} }
@ -175,8 +175,8 @@ void MainWidget::initRightWindow()
titleWidget->setFixedHeight(62); titleWidget->setFixedHeight(62);
titleWidget->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed); titleWidget->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed);
titleWidget->setObjectName("titleWidget"); titleWidget->setObjectName("titleWidget");
titleWidget->setStyleSheet(R"(#titleWidget { border-bottom: 1px solid rgb(230, 230, 230); titleWidget->setStyleSheet(R"(#titleWidget { border-bottom: 2px solid rgb(231, 231, 231);
border-left: 1px solid rgb(230, 230, 230); } border-left: 1px solid rgb(231, 231, 231); }
)"); )");
vlayout->addWidget(titleWidget); vlayout->addWidget(titleWidget);

View File

@ -19,6 +19,55 @@ MessageShowArea::MessageShowArea() {
layout->setSpacing(0); layout->setSpacing(0);
layout->setContentsMargins(0, 0, 0, 0); layout->setContentsMargins(0, 0, 0, 0);
container->setLayout(layout); 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<QVBoxLayout*>(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); MessageItem* messageItem = new MessageItem(isLeft);
QGridLayout* layout = new QGridLayout(); QGridLayout* layout = new QGridLayout();
layout->setSpacing(0); layout->setSpacing(10);
layout->setContentsMargins(0, 0, 0, 0); layout->setContentsMargins(30, 10, 40, 0);
//这个message最低不能低于100 //这个message最低不能低于100
messageItem->setMinimumHeight(100); messageItem->setMinimumHeight(100);
@ -48,9 +97,9 @@ MessageItem *MessageItem::makeMessageItem(bool isLeft, const Message &message)
avatarBtn->setIconSize(QSize(40, 40)); avatarBtn->setIconSize(QSize(40, 40));
avatarBtn->setIcon(message.sender.avatar); avatarBtn->setIcon(message.sender.avatar);
if(isLeft) { 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 { } 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; 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<QWidget*>(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);
}

View File

@ -7,8 +7,12 @@
#include <QScrollBar> #include <QScrollBar>
#include <QPushButton> #include <QPushButton>
#include <QLabel> #include <QLabel>
#include <QFontMetrics>
#include <QPainter>
#include <QPainterPath>
#include "model/data.h" #include "model/data.h"
#include "debug.h"
//.h文件中不宜使用namespace xxx //.h文件中不宜使用namespace xxx
using model::Message; using model::Message;
@ -22,6 +26,14 @@ class MessageShowArea : public QScrollArea
public: public:
MessageShowArea(); MessageShowArea();
//头插
void addFrontMessage(bool isLeft, const Message& message);
//尾插
void addMessage(bool isLeft, const Message& message);
//清空
void clear();
private: private:
QWidget* container; QWidget* container;
}; };
@ -38,8 +50,28 @@ public:
//通过工厂方法创建MessageItem实例 //通过工厂方法创建MessageItem实例
static MessageItem* makeMessageItem(bool isLeft, const Message& message); 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: private:
bool isLeft; 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 #endif // MESSAGESHOWAREA_H

View File

@ -17,7 +17,7 @@ SessionFriendArea::SessionFriendArea(QWidget *parent)
this->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff); this->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
this->verticalScrollBar()->setStyleSheet(R"( this->verticalScrollBar()->setStyleSheet(R"(
QScrollBar:vertical { QScrollBar:vertical {
background-color: rgb(231, 231, 231); /* 滚动条背景透明 */ background-color: rgb(228, 228, 228); /* 滚动条背景透明 */
width: 6px; /* 默认宽度 */ width: 6px; /* 默认宽度 */
margin: 0px 0px 0px 0px; /* 边距清零 */ margin: 0px 0px 0px 0px; /* 边距清零 */
} }
@ -84,7 +84,7 @@ SessionFriendItem::SessionFriendItem(QWidget* owner, const QIcon& avatar, const
{ {
this->setFixedHeight(70); 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(avatarBtn, 0, 0, 2, 2);
layout->addWidget(nameLabel, 0, 2, 1, 8); layout->addWidget(nameLabel, 0, 2, 1, 25);
layout->addWidget(messageLabel, 1, 2, 1, 8); layout->addWidget(messageLabel, 1, 2, 1, 25);
} }
void SessionFriendItem::paintEvent(QPaintEvent *event) void SessionFriendItem::paintEvent(QPaintEvent *event)
@ -150,7 +150,7 @@ void SessionFriendItem::enterEvent(QEvent *event)
return; return;
} }
this->setStyleSheet("QWidget { background-color: rgb(220, 220, 220); }"); this->setStyleSheet("QWidget { background-color: rgb(215, 215, 215); }");
} }
void SessionFriendItem::leaveEvent(QEvent *event) void SessionFriendItem::leaveEvent(QEvent *event)
@ -161,7 +161,7 @@ void SessionFriendItem::leaveEvent(QEvent *event)
return; return;
} }
this->setStyleSheet("QWidget { background-color: rgb(231, 231, 231); }"); this->setStyleSheet("QWidget { background-color: rgb(228, 228, 228); }");
} }
void SessionFriendItem::select() void SessionFriendItem::select()
@ -176,12 +176,12 @@ void SessionFriendItem::select()
SessionFriendItem* item = dynamic_cast<SessionFriendItem*>(child); SessionFriendItem* item = dynamic_cast<SessionFriendItem*>(child);
if(item->selected) { if(item->selected) {
item->selected = false; 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; this->selected = true;
//调用Active //调用Active