├── .gitignore
├── Demo_MessageChat_Qt.pro
├── README.md
├── chatmessage
├── qnchatmessage.cpp
└── qnchatmessage.h
├── img.qrc
├── img
├── Customer Copy.png
├── CustomerService.png
└── loading4.gif
├── main.cpp
├── mainwindow.cpp
├── mainwindow.h
├── mainwindow.ui
├── 效果1.png
└── 效果2.png
/.gitignore:
--------------------------------------------------------------------------------
1 | # C++ objects and libs
2 | *.slo
3 | *.lo
4 | *.o
5 | *.a
6 | *.la
7 | *.lai
8 | *.so
9 | *.so.*
10 | *.dll
11 | *.dylib
12 |
13 | # Qt-es
14 | object_script.*.Release
15 | object_script.*.Debug
16 | *_plugin_import.cpp
17 | /.qmake.cache
18 | /.qmake.stash
19 | *.pro.user
20 | *.pro.user.*
21 | *.qbs.user
22 | *.qbs.user.*
23 | *.moc
24 | moc_*.cpp
25 | moc_*.h
26 | qrc_*.cpp
27 | ui_*.h
28 | *.qmlc
29 | *.jsc
30 | Makefile*
31 | *build-*
32 | *.qm
33 | *.prl
34 |
35 | # Qt unit tests
36 | target_wrapper.*
37 |
38 | # QtCreator
39 | *.autosave
40 |
41 | # QtCreator Qml
42 | *.qmlproject.user
43 | *.qmlproject.user.*
44 |
45 | # QtCreator CMake
46 | CMakeLists.txt.user*
47 |
48 | # QtCreator 4.8< compilation database
49 | compile_commands.json
50 |
51 | # QtCreator local machine specific files for imported projects
52 | *creator.user*
53 |
--------------------------------------------------------------------------------
/Demo_MessageChat_Qt.pro:
--------------------------------------------------------------------------------
1 | #-------------------------------------------------
2 | #
3 | # Project created by QtCreator 2018-07-23 沙振宇
4 | #
5 | #-------------------------------------------------
6 | QT += core gui
7 |
8 | greaterThan(QT_MAJOR_VERSION, 4): QT += widgets
9 |
10 | TARGET = Demo_MessageChat
11 | TEMPLATE = app
12 |
13 |
14 | SOURCES += main.cpp\
15 | mainwindow.cpp \
16 | chatmessage/qnchatmessage.cpp
17 |
18 | HEADERS += mainwindow.h \
19 | chatmessage/qnchatmessage.h
20 |
21 | FORMS += mainwindow.ui
22 |
23 | RESOURCES += \
24 | img.qrc
25 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # 1、Qt的应用开发 之 Demo_MessageChat_Qt
2 | Qt5气泡式聊天框——QListWidget+QPainter。
3 | 气泡式聊天的显示是由QListWidget作为控件,每个气泡是由QListWidgetItem提升成QWidget来实现的。每个气泡可以理解为可以自由布置里面内容的QWidget。每个Item保存聊天的对话、发送状态、时间、种类等。这个QWidget主要是显示一个头像+气泡,气泡里面是聊天的内容等。气泡是在paintEvent事件中,采用QPainter来绘制的。
4 |
5 | # 2、更新信息
6 | 开发者:沙振宇(沙师弟专栏)
7 | 创建时间:2018-07-23
8 | 最后一次更新时间:2019-12-27
9 | 此项目CSDN博客:Qt5气泡式聊天框——QListWidget+QPainter实现
10 | 此项目博客地址:https://shazhenyu.blog.csdn.net/article/details/81505832
11 |
12 | # 3、效果
13 | 
14 | 
--------------------------------------------------------------------------------
/chatmessage/qnchatmessage.cpp:
--------------------------------------------------------------------------------
1 | /*-------------------------------------------------
2 | #
3 | # Project created by QtCreator
4 | # Author: 沙振宇
5 | # CreateTime: 2018-07-23
6 | # UpdateTime: 2019-12-27
7 | # Info: Qt5气泡式聊天框——QListWidget+QPainter实现
8 | # Url:https://shazhenyu.blog.csdn.net/article/details/81505832
9 | # Github:https://github.com/ShaShiDiZhuanLan/Demo_MessageChat_Qt
10 | #
11 | #-------------------------------------------------*/
12 | #include "qnchatmessage.h"
13 | #include
14 | #include
15 | #include
16 | #include
17 | #include
18 | #include
19 | #include
20 |
21 | QNChatMessage::QNChatMessage(QWidget *parent) : QWidget(parent)
22 | {
23 | QFont te_font = this->font();
24 | te_font.setFamily("MicrosoftYaHei");
25 | te_font.setPointSize(12);
26 | // te_font.setWordSpacing(0);
27 | // te_font.setLetterSpacing(QFont::PercentageSpacing,0);
28 | // te_font.setLetterSpacing(QFont::PercentageSpacing, 100); //300%,100为默认 //设置字间距%
29 | // te_font.setLetterSpacing(QFont::AbsoluteSpacing, 0); //设置字间距为3像素 //设置字间距像素值
30 | this->setFont(te_font);
31 | m_leftPixmap = QPixmap(":/img/Customer Copy.png");
32 | m_rightPixmap = QPixmap(":/img/CustomerService.png");
33 |
34 | m_loadingMovie = new QMovie(this);
35 | m_loadingMovie->setFileName(":/img/loading4.gif");
36 | m_loading = new QLabel(this);
37 | m_loading->setMovie(m_loadingMovie);
38 | m_loading->resize(16,16);
39 | m_loading->setAttribute(Qt::WA_TranslucentBackground , true);
40 | m_loading->setAutoFillBackground(false);
41 | }
42 |
43 | void QNChatMessage::setTextSuccess()
44 | {
45 | m_loading->hide();
46 | m_loadingMovie->stop();
47 | m_isSending = true;
48 | }
49 |
50 | void QNChatMessage::setText(QString text, QString time, QSize allSize, QNChatMessage::User_Type userType)
51 | {
52 | m_msg = text;
53 | m_userType = userType;
54 | m_time = time;
55 | m_curTime = QDateTime::fromTime_t(time.toInt()).toString("hh:mm");
56 | m_allSize = allSize;
57 | if(userType == User_Me) {
58 | if(!m_isSending) {
59 | m_loading->move(m_kuangRightRect.x() - m_loading->width() - 10, m_kuangRightRect.y()+m_kuangRightRect.height()/2- m_loading->height()/2);
60 | m_loading->show();
61 | m_loadingMovie->start();
62 | }
63 | } else {
64 | m_loading->hide();
65 | }
66 |
67 | this->update();
68 | }
69 |
70 | QSize QNChatMessage::fontRect(QString str)
71 | {
72 | m_msg = str;
73 | int minHei = 30;
74 | int iconWH = 40;
75 | int iconSpaceW = 20;
76 | int iconRectW = 5;
77 | int iconTMPH = 10;
78 | int sanJiaoW = 6;
79 | int kuangTMP = 20;
80 | int textSpaceRect = 12;
81 | m_kuangWidth = this->width() - kuangTMP - 2*(iconWH+iconSpaceW+iconRectW);
82 | m_textWidth = m_kuangWidth - 2*textSpaceRect;
83 | m_spaceWid = this->width() - m_textWidth;
84 | m_iconLeftRect = QRect(iconSpaceW, iconTMPH, iconWH, iconWH);
85 | m_iconRightRect = QRect(this->width() - iconSpaceW - iconWH, iconTMPH, iconWH, iconWH);
86 |
87 | QSize size = getRealString(m_msg); // 整个的size
88 |
89 | qDebug() << "fontRect Size:" << size;
90 | int hei = size.height() < minHei ? minHei : size.height();
91 |
92 | m_sanjiaoLeftRect = QRect(iconWH+iconSpaceW+iconRectW, m_lineHeight/2, sanJiaoW, hei - m_lineHeight);
93 | m_sanjiaoRightRect = QRect(this->width() - iconRectW - iconWH - iconSpaceW - sanJiaoW, m_lineHeight/2, sanJiaoW, hei - m_lineHeight);
94 |
95 | if(size.width() < (m_textWidth+m_spaceWid)) {
96 | m_kuangLeftRect.setRect(m_sanjiaoLeftRect.x()+m_sanjiaoLeftRect.width(), m_lineHeight/4*3, size.width()-m_spaceWid+2*textSpaceRect, hei-m_lineHeight);
97 | m_kuangRightRect.setRect(this->width() - size.width() + m_spaceWid - 2*textSpaceRect - iconWH - iconSpaceW - iconRectW - sanJiaoW,
98 | m_lineHeight/4*3, size.width()-m_spaceWid+2*textSpaceRect, hei-m_lineHeight);
99 | } else {
100 | m_kuangLeftRect.setRect(m_sanjiaoLeftRect.x()+m_sanjiaoLeftRect.width(), m_lineHeight/4*3, m_kuangWidth, hei-m_lineHeight);
101 | m_kuangRightRect.setRect(iconWH + kuangTMP + iconSpaceW + iconRectW - sanJiaoW, m_lineHeight/4*3, m_kuangWidth, hei-m_lineHeight);
102 | }
103 | m_textLeftRect.setRect(m_kuangLeftRect.x()+textSpaceRect,m_kuangLeftRect.y()+iconTMPH,
104 | m_kuangLeftRect.width()-2*textSpaceRect,m_kuangLeftRect.height()-2*iconTMPH);
105 | m_textRightRect.setRect(m_kuangRightRect.x()+textSpaceRect,m_kuangRightRect.y()+iconTMPH,
106 | m_kuangRightRect.width()-2*textSpaceRect,m_kuangRightRect.height()-2*iconTMPH);
107 |
108 | return QSize(size.width(), hei);
109 | }
110 |
111 | QSize QNChatMessage::getRealString(QString src)
112 | {
113 | QFontMetricsF fm(this->font());
114 | m_lineHeight = fm.lineSpacing();
115 | int nCount = src.count("\n");
116 | int nMaxWidth = 0;
117 | if(nCount == 0) {
118 | nMaxWidth = fm.width(src);
119 | QString value = src;
120 | if(nMaxWidth > m_textWidth) {
121 | nMaxWidth = m_textWidth;
122 | int size = m_textWidth / fm.width(" ");
123 | int num = fm.width(value) / m_textWidth;
124 | int ttmp = num*fm.width(" ");
125 | num = ( fm.width(value) ) / m_textWidth;
126 | nCount += num;
127 | QString temp = "";
128 | for(int i = 0; i < num; i++) {
129 | temp += value.mid(i*size, (i+1)*size) + "\n";
130 | }
131 | src.replace(value, temp);
132 | }
133 | } else {
134 | for(int i = 0; i < (nCount + 1); i++) {
135 | QString value = src.split("\n").at(i);
136 | nMaxWidth = fm.width(value) > nMaxWidth ? fm.width(value) : nMaxWidth;
137 | if(fm.width(value) > m_textWidth) {
138 | nMaxWidth = m_textWidth;
139 | int size = m_textWidth / fm.width(" ");
140 | int num = fm.width(value) / m_textWidth;
141 | num = ((i+num)*fm.width(" ") + fm.width(value)) / m_textWidth;
142 | nCount += num;
143 | QString temp = "";
144 | for(int i = 0; i < num; i++) {
145 | temp += value.mid(i*size, (i+1)*size) + "\n";
146 | }
147 | src.replace(value, temp);
148 | }
149 | }
150 | }
151 | return QSize(nMaxWidth+m_spaceWid, (nCount + 1) * m_lineHeight+2*m_lineHeight);
152 | }
153 |
154 | void QNChatMessage::paintEvent(QPaintEvent *event)
155 | {
156 | Q_UNUSED(event);
157 |
158 | QPainter painter(this);
159 | painter.setRenderHints(QPainter::Antialiasing | QPainter::SmoothPixmapTransform);//消锯齿
160 | painter.setPen(Qt::NoPen);
161 | painter.setBrush(QBrush(Qt::gray));
162 |
163 | if(m_userType == User_Type::User_She) { // 用户
164 | //头像
165 | // painter.drawRoundedRect(m_iconLeftRect,m_iconLeftRect.width(),m_iconLeftRect.height());
166 | painter.drawPixmap(m_iconLeftRect, m_leftPixmap);
167 |
168 | //框加边
169 | QColor col_KuangB(234, 234, 234);
170 | painter.setBrush(QBrush(col_KuangB));
171 | painter.drawRoundedRect(m_kuangLeftRect.x()-1,m_kuangLeftRect.y()-1,m_kuangLeftRect.width()+2,m_kuangLeftRect.height()+2,4,4);
172 | //框
173 | QColor col_Kuang(255,255,255);
174 | painter.setBrush(QBrush(col_Kuang));
175 | painter.drawRoundedRect(m_kuangLeftRect,4,4);
176 |
177 | //三角
178 | QPointF points[3] = {
179 | QPointF(m_sanjiaoLeftRect.x(), 30),
180 | QPointF(m_sanjiaoLeftRect.x()+m_sanjiaoLeftRect.width(), 25),
181 | QPointF(m_sanjiaoLeftRect.x()+m_sanjiaoLeftRect.width(), 35),
182 | };
183 | QPen pen;
184 | pen.setColor(col_Kuang);
185 | painter.setPen(pen);
186 | painter.drawPolygon(points, 3);
187 |
188 | //三角加边
189 | QPen penSanJiaoBian;
190 | penSanJiaoBian.setColor(col_KuangB);
191 | painter.setPen(penSanJiaoBian);
192 | painter.drawLine(QPointF(m_sanjiaoLeftRect.x() - 1, 30), QPointF(m_sanjiaoLeftRect.x()+m_sanjiaoLeftRect.width(), 24));
193 | painter.drawLine(QPointF(m_sanjiaoLeftRect.x() - 1, 30), QPointF(m_sanjiaoLeftRect.x()+m_sanjiaoLeftRect.width(), 36));
194 |
195 | //内容
196 | QPen penText;
197 | penText.setColor(QColor(51,51,51));
198 | painter.setPen(penText);
199 | QTextOption option(Qt::AlignLeft | Qt::AlignVCenter);
200 | option.setWrapMode(QTextOption::WrapAtWordBoundaryOrAnywhere);
201 | painter.setFont(this->font());
202 | painter.drawText(m_textLeftRect, m_msg,option);
203 | } else if(m_userType == User_Type::User_Me) { // 自己
204 | //头像
205 | // painter.drawRoundedRect(m_iconRightRect,m_iconRightRect.width(),m_iconRightRect.height());
206 | painter.drawPixmap(m_iconRightRect, m_rightPixmap);
207 |
208 | //框
209 | QColor col_Kuang(75,164,242);
210 | painter.setBrush(QBrush(col_Kuang));
211 | painter.drawRoundedRect(m_kuangRightRect,4,4);
212 |
213 | //三角
214 | QPointF points[3] = {
215 | QPointF(m_sanjiaoRightRect.x()+m_sanjiaoRightRect.width(), 30),
216 | QPointF(m_sanjiaoRightRect.x(), 25),
217 | QPointF(m_sanjiaoRightRect.x(), 35),
218 | };
219 | QPen pen;
220 | pen.setColor(col_Kuang);
221 | painter.setPen(pen);
222 | painter.drawPolygon(points, 3);
223 |
224 | //内容
225 | QPen penText;
226 | penText.setColor(Qt::white);
227 | painter.setPen(penText);
228 | QTextOption option(Qt::AlignLeft | Qt::AlignVCenter);
229 | option.setWrapMode(QTextOption::WrapAtWordBoundaryOrAnywhere);
230 | painter.setFont(this->font());
231 | painter.drawText(m_textRightRect,m_msg,option);
232 | } else if(m_userType == User_Type::User_Time) { // 时间
233 | QPen penText;
234 | penText.setColor(QColor(153,153,153));
235 | painter.setPen(penText);
236 | QTextOption option(Qt::AlignCenter);
237 | option.setWrapMode(QTextOption::WrapAtWordBoundaryOrAnywhere);
238 | QFont te_font = this->font();
239 | te_font.setFamily("MicrosoftYaHei");
240 | te_font.setPointSize(10);
241 | painter.setFont(te_font);
242 | painter.drawText(this->rect(),m_curTime,option);
243 | }
244 | }
245 |
--------------------------------------------------------------------------------
/chatmessage/qnchatmessage.h:
--------------------------------------------------------------------------------
1 | /*-------------------------------------------------
2 | #
3 | # Project created by QtCreator
4 | # Author: 沙振宇
5 | # CreateTime: 2018-07-23
6 | # UpdateTime: 2019-12-27
7 | # Info: Qt5气泡式聊天框——QListWidget+QPainter实现
8 | # Url:https://shazhenyu.blog.csdn.net/article/details/81505832
9 | # Github:https://github.com/ShaShiDiZhuanLan/Demo_MessageChat_Qt
10 | #
11 | #-------------------------------------------------*/
12 | #ifndef QNCHATMESSAGE_H
13 | #define QNCHATMESSAGE_H
14 |
15 | #include
16 |
17 | class QPaintEvent;
18 | class QPainter;
19 | class QLabel;
20 | class QMovie;
21 |
22 | class QNChatMessage : public QWidget
23 | {
24 | Q_OBJECT
25 | public:
26 | explicit QNChatMessage(QWidget *parent = nullptr);
27 |
28 | enum User_Type{
29 | User_System,//系统
30 | User_Me, //自己
31 | User_She, //用户
32 | User_Time, //时间
33 | };
34 | void setTextSuccess();
35 | void setText(QString text, QString time, QSize allSize, User_Type userType);
36 |
37 | QSize getRealString(QString src);
38 | QSize fontRect(QString str);
39 |
40 | inline QString text() {return m_msg;}
41 | inline QString time() {return m_time;}
42 | inline User_Type userType() {return m_userType;}
43 | protected:
44 | void paintEvent(QPaintEvent *event);
45 | private:
46 | QString m_msg;
47 | QString m_time;
48 | QString m_curTime;
49 |
50 | QSize m_allSize;
51 | User_Type m_userType = User_System;
52 |
53 | int m_kuangWidth;
54 | int m_textWidth;
55 | int m_spaceWid;
56 | int m_lineHeight;
57 |
58 | QRect m_iconLeftRect;
59 | QRect m_iconRightRect;
60 | QRect m_sanjiaoLeftRect;
61 | QRect m_sanjiaoRightRect;
62 | QRect m_kuangLeftRect;
63 | QRect m_kuangRightRect;
64 | QRect m_textLeftRect;
65 | QRect m_textRightRect;
66 | QPixmap m_leftPixmap;
67 | QPixmap m_rightPixmap;
68 | QLabel* m_loading = Q_NULLPTR;
69 | QMovie* m_loadingMovie = Q_NULLPTR;
70 | bool m_isSending = false;
71 | };
72 |
73 | #endif // QNCHATMESSAGE_H
74 |
--------------------------------------------------------------------------------
/img.qrc:
--------------------------------------------------------------------------------
1 |
2 |
3 | img/Customer Copy.png
4 | img/CustomerService.png
5 | img/loading4.gif
6 |
7 |
8 |
--------------------------------------------------------------------------------
/img/Customer Copy.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ShaShiDiZhuanLan/Demo_MessageChat_Qt/103428fb8080401e0bd6093aafc5e76b2b37effe/img/Customer Copy.png
--------------------------------------------------------------------------------
/img/CustomerService.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ShaShiDiZhuanLan/Demo_MessageChat_Qt/103428fb8080401e0bd6093aafc5e76b2b37effe/img/CustomerService.png
--------------------------------------------------------------------------------
/img/loading4.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ShaShiDiZhuanLan/Demo_MessageChat_Qt/103428fb8080401e0bd6093aafc5e76b2b37effe/img/loading4.gif
--------------------------------------------------------------------------------
/main.cpp:
--------------------------------------------------------------------------------
1 | /*-------------------------------------------------
2 | #
3 | # Project created by QtCreator
4 | # Author: 沙振宇
5 | # CreateTime: 2018-07-23
6 | # UpdateTime: 2019-12-27
7 | # Info: Qt5气泡式聊天框——QListWidget+QPainter实现
8 | # Url:https://shazhenyu.blog.csdn.net/article/details/81505832
9 | # Github:https://github.com/ShaShiDiZhuanLan/Demo_MessageChat_Qt
10 | #
11 | #-------------------------------------------------*/
12 | #include "mainwindow.h"
13 | #include
14 |
15 | int main(int argc, char *argv[])
16 | {
17 | QApplication a(argc, argv);
18 | MainWindow w;
19 | w.show();
20 |
21 | return a.exec();
22 | }
23 |
--------------------------------------------------------------------------------
/mainwindow.cpp:
--------------------------------------------------------------------------------
1 | /*-------------------------------------------------
2 | #
3 | # Project created by QtCreator
4 | # Author: 沙振宇
5 | # CreateTime: 2018-07-23
6 | # UpdateTime: 2019-12-27
7 | # Info: Qt5气泡式聊天框——QListWidget+QPainter实现
8 | # Url:https://shazhenyu.blog.csdn.net/article/details/81505832
9 | # Github:https://github.com/ShaShiDiZhuanLan/Demo_MessageChat_Qt
10 | #
11 | #-------------------------------------------------*/
12 | #include "mainwindow.h"
13 | #include "ui_mainwindow.h"
14 | #include
15 | #include
16 |
17 | MainWindow::MainWindow(QWidget *parent) :
18 | QMainWindow(parent),
19 | ui(new Ui::MainWindow)
20 | {
21 | ui->setupUi(this);
22 |
23 | resize(600, 800);
24 | }
25 |
26 | MainWindow::~MainWindow()
27 | {
28 | delete ui;
29 | }
30 |
31 | void MainWindow::on_pushButton_clicked()
32 | {
33 | QString msg = ui->textEdit->toPlainText();
34 | ui->textEdit->setText("");
35 | QString time = QString::number(QDateTime::currentDateTime().toTime_t()); //时间戳
36 |
37 | bool isSending = true; // 发送中
38 |
39 | qDebug()<<"addMessage" << msg << time << ui->listWidget->count();
40 | if(ui->listWidget->count()%2) {
41 | if(isSending) {
42 | dealMessageTime(time);
43 |
44 | QNChatMessage* messageW = new QNChatMessage(ui->listWidget->parentWidget());
45 | QListWidgetItem* item = new QListWidgetItem(ui->listWidget);
46 | dealMessage(messageW, item, msg, time, QNChatMessage::User_Me);
47 | } else {
48 | bool isOver = true;
49 | for(int i = ui->listWidget->count() - 1; i > 0; i--) {
50 | QNChatMessage* messageW = (QNChatMessage*)ui->listWidget->itemWidget(ui->listWidget->item(i));
51 | if(messageW->text() == msg) {
52 | isOver = false;
53 | messageW->setTextSuccess();
54 | }
55 | }
56 | if(isOver) {
57 | dealMessageTime(time);
58 |
59 | QNChatMessage* messageW = new QNChatMessage(ui->listWidget->parentWidget());
60 | QListWidgetItem* item = new QListWidgetItem(ui->listWidget);
61 | dealMessage(messageW, item, msg, time, QNChatMessage::User_Me);
62 | messageW->setTextSuccess();
63 | }
64 | }
65 | } else {
66 | if(msg != "") {
67 | dealMessageTime(time);
68 |
69 | QNChatMessage* messageW = new QNChatMessage(ui->listWidget->parentWidget());
70 | QListWidgetItem* item = new QListWidgetItem(ui->listWidget);
71 | dealMessage(messageW, item, msg, time, QNChatMessage::User_She);
72 | }
73 | }
74 | ui->listWidget->setCurrentRow(ui->listWidget->count()-1);
75 | }
76 |
77 | void MainWindow::dealMessage(QNChatMessage *messageW, QListWidgetItem *item, QString text, QString time, QNChatMessage::User_Type type)
78 | {
79 | messageW->setFixedWidth(this->width());
80 | QSize size = messageW->fontRect(text);
81 | item->setSizeHint(size);
82 | messageW->setText(text, time, size, type);
83 | ui->listWidget->setItemWidget(item, messageW);
84 | }
85 |
86 | void MainWindow::dealMessageTime(QString curMsgTime)
87 | {
88 | bool isShowTime = false;
89 | if(ui->listWidget->count() > 0) {
90 | QListWidgetItem* lastItem = ui->listWidget->item(ui->listWidget->count() - 1);
91 | QNChatMessage* messageW = (QNChatMessage*)ui->listWidget->itemWidget(lastItem);
92 | int lastTime = messageW->time().toInt();
93 | int curTime = curMsgTime.toInt();
94 | qDebug() << "curTime lastTime:" << curTime - lastTime;
95 | isShowTime = ((curTime - lastTime) > 60); // 两个消息相差一分钟
96 | // isShowTime = true;
97 | } else {
98 | isShowTime = true;
99 | }
100 | if(isShowTime) {
101 | QNChatMessage* messageTime = new QNChatMessage(ui->listWidget->parentWidget());
102 | QListWidgetItem* itemTime = new QListWidgetItem(ui->listWidget);
103 |
104 | QSize size = QSize(this->width(), 40);
105 | messageTime->resize(size);
106 | itemTime->setSizeHint(size);
107 | messageTime->setText(curMsgTime, curMsgTime, size, QNChatMessage::User_Time);
108 | ui->listWidget->setItemWidget(itemTime, messageTime);
109 | }
110 | }
111 |
112 | void MainWindow::resizeEvent(QResizeEvent *event)
113 | {
114 | Q_UNUSED(event);
115 |
116 |
117 | ui->textEdit->resize(this->width() - 20, ui->widget->height() - 20);
118 | ui->textEdit->move(10, 10);
119 |
120 | ui->pushButton->move(ui->textEdit->width()+ui->textEdit->x() - ui->pushButton->width() - 10,
121 | ui->textEdit->height()+ui->textEdit->y() - ui->pushButton->height() - 10);
122 |
123 |
124 | for(int i = 0; i < ui->listWidget->count(); i++) {
125 | QNChatMessage* messageW = (QNChatMessage*)ui->listWidget->itemWidget(ui->listWidget->item(i));
126 | QListWidgetItem* item = ui->listWidget->item(i);
127 |
128 | dealMessage(messageW, item, messageW->text(), messageW->time(), messageW->userType());
129 | }
130 | }
131 |
--------------------------------------------------------------------------------
/mainwindow.h:
--------------------------------------------------------------------------------
1 | /*-------------------------------------------------
2 | #
3 | # Project created by QtCreator
4 | # Author: 沙振宇
5 | # CreateTime: 2018-07-23
6 | # UpdateTime: 2019-12-27
7 | # Info: Qt5气泡式聊天框——QListWidget+QPainter实现
8 | # Url:https://shazhenyu.blog.csdn.net/article/details/81505832
9 | # Github:https://github.com/ShaShiDiZhuanLan/Demo_MessageChat_Qt
10 | #
11 | #-------------------------------------------------*/
12 | #ifndef MAINWINDOW_H
13 | #define MAINWINDOW_H
14 |
15 | #include
16 | #include
17 | #include "chatmessage/qnchatmessage.h"
18 |
19 | namespace Ui {
20 | class MainWindow;
21 | }
22 |
23 | class MainWindow : public QMainWindow
24 | {
25 | Q_OBJECT
26 |
27 | public:
28 | explicit MainWindow(QWidget *parent = 0);
29 | ~MainWindow();
30 |
31 | void dealMessage(QNChatMessage *messageW, QListWidgetItem *item, QString text, QString time, QNChatMessage::User_Type type);
32 | void dealMessageTime(QString curMsgTime);
33 | protected:
34 | void resizeEvent(QResizeEvent *event);
35 | private slots:
36 | void on_pushButton_clicked();
37 |
38 | private:
39 | Ui::MainWindow *ui;
40 | };
41 |
42 | #endif // MAINWINDOW_H
43 |
--------------------------------------------------------------------------------
/mainwindow.ui:
--------------------------------------------------------------------------------
1 |
2 |
3 | MainWindow
4 |
5 |
6 |
7 | 0
8 | 0
9 | 693
10 | 626
11 |
12 |
13 |
14 | MainWindow
15 |
16 |
17 |
18 |
19 | 0
20 |
21 |
22 | 0
23 |
24 |
25 | 0
26 |
27 |
28 | 0
29 |
30 |
31 | 0
32 |
33 | -
34 |
35 |
36 |
37 | 0
38 | 0
39 |
40 |
41 |
42 | QListWidget{background-color: rgb(247, 247, 247); color:rgb(51,51,51); border: 1px solid rgb(247, 247, 247);outline:0px;}
43 | QListWidget::Item{background-color: rgb(247, 247, 247);}
44 | QListWidget::Item:hover{background-color: rgb(247, 247, 247); }
45 | QListWidget::item:selected{
46 | background-color: rgb(247, 247, 247);
47 | color:black;
48 | border: 1px solid rgb(247, 247, 247);
49 | }
50 | QListWidget::item:selected:!active{border: 1px solid rgb(247, 247, 247); background-color: rgb(247, 247, 247); color:rgb(51,51,51); }
51 |
52 |
53 | Qt::ScrollBarAsNeeded
54 |
55 |
56 | Qt::ScrollBarAlwaysOff
57 |
58 |
59 |
60 | -
61 |
62 |
63 |
64 | 0
65 | 200
66 |
67 |
68 |
69 |
70 | 16777215
71 | 200
72 |
73 |
74 |
75 |
76 |
77 | 10
78 | 10
79 | 561
80 | 151
81 |
82 |
83 |
84 |
85 | 0
86 | 0
87 |
88 |
89 |
90 |
91 |
92 |
93 | 440
94 | 120
95 | 81
96 | 23
97 |
98 |
99 |
100 | 发送
101 |
102 |
103 |
104 |
105 |
106 |
107 |
108 |
109 |
110 |
111 |
112 |
--------------------------------------------------------------------------------
/效果1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ShaShiDiZhuanLan/Demo_MessageChat_Qt/103428fb8080401e0bd6093aafc5e76b2b37effe/效果1.png
--------------------------------------------------------------------------------
/效果2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ShaShiDiZhuanLan/Demo_MessageChat_Qt/103428fb8080401e0bd6093aafc5e76b2b37effe/效果2.png
--------------------------------------------------------------------------------