聊天消息框
公司最近需要使用qt开发一个局域网聊天工具,网上找了好多例子,也参考了好多文章,都不太理想,最后查到雨田哥写的使用QtWebEngine,实现了基本的功能,但是发送消息加换行也存在问题,自己也摸索了很长时间,现贴出代码,基本的效果有,但是展示还不太完美,做个引子吧,也咨询了一些大佬说要么自己封装控件,要么使用QWebView可能能满足需求,想了想还是应该使用QWebView比较简单吧,后面有时间了,自己实现下,欢迎大家做这方面的互相学习,共同分享交流:
效果图:
代码:
#define MAINWINDOW_H
#include
#include
#include
#include
#include
#include
#include
#include
class QHBoxLayout;
class QVBoxLayout;
typedef struct Message
{
QString name; //消息发送者名称
QString icon; //消息发送者头像
QString datetime; //消息时间
QString type; //消息类型 image,file,message
QString direct; //消息方向 Send Receive
QString message_id; //消息id {fdsfasdf-fewfewfe-ewfwe-fewf-fewfwefwef}
QString content; //消息内容 消息内容,文件全路径
QString filename; //文件名称
QString filesize; //文件大小
}Message;
class MessageFrame : public QFrame
{
Q_OBJECT
public:
explicit MessageFrame(Message msg, QWidget *parent = nullptr);
~MessageFrame()override;
private:
void initUI();
QHBoxLayout* m_mainLayout;
Message m_pCurMessage;
QTextEdit* m_messageEdit;
private slots:
void adjustContent();
};
class ChatFrame : public QScrollArea
{
Q_OBJECT
public:
explicit ChatFrame(QWidget* parent = nullptr);
~ChatFrame()override;
//添加消息
void addMessage(Message msg);
private:
QVBoxLayout* m_vLayout;
QScrollBar* m_verticalBar;
QLabel *m_pHistoryLabel;
QList m_pMessages;
};
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
explicit MainWindow(QWidget *parent = nullptr);
~MainWindow()override;
protected:
bool eventFilter(QObject *object, QEvent *event)override;
private:
QWidget *m_mainWidget;
ChatFrame* m_chatWidget;
QTextEdit *m_sendTextEdit;
QVBoxLayout *m_vBoxLayout;
void initUI();
void sendMessage();
};
#endif // MAINWINDOW_H
```cpp
#include "mainwindow.h"
#include
#include
#include
#include
#include
#include
MessageFrame::MessageFrame(Message msg, QWidget* parent)
: QFrame (parent)
{
m_mainLayout = new QHBoxLayout;
m_pCurMessage = msg;
initUI();
setLayout(m_mainLayout);
m_mainLayout->setContentsMargins(0,0,0,0);
setFrameShape(QFrame::NoFrame);
this->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Preferred);
}
MessageFrame::~MessageFrame()
{
}
void MessageFrame::initUI()
{
QVBoxLayout* play = new QVBoxLayout;
m_messageEdit = new QTextEdit;
connect(m_messageEdit->document(),&QTextDocument::contentsChange,this,&MessageFrame::adjustContent);
m_messageEdit->setMaximumWidth(300);
m_messageEdit->setText(m_pCurMessage.content);
m_messageEdit->setTextColor(Qt::white);
m_messageEdit->setReadOnly(true);
m_messageEdit->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
m_messageEdit->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
m_messageEdit->setStyleSheet("background-color:rgba(0,129,255,1); color:white;border-radius:5px;");
m_messageEdit->viewport()->setContentsMargins(20,0,20,0);
m_messageEdit->setMouseTracking(true);
m_messageEdit->viewport()->setMouseTracking(true);
m_messageEdit->viewport()->installEventFilter(this);
m_messageEdit->setAlignment(Qt::AlignLeft);
QHBoxLayout* pl = new QHBoxLayout;
pl->addStretch(10);
pl->addWidget(m_messageEdit);
play->addLayout(pl);
play->setSpacing(10);
m_mainLayout->addLayout(play);
}
void MessageFrame::adjustContent()
{
QTextDocument *document=qobject_cast(sender());
document->adjustSize();
if(document)
{
document->setDocumentMargin(8);
QTextEdit *editor = qobject_cast(document->parent()->parent());
if (editor) {
QString text = editor->toPlainText().trimmed();
if (text.isEmpty()) {
return;
}
QFontMetrics mert = editor->viewport()->fontMetrics();
int nCount = text.count("\n");
int width = mert.width(text);
int height = mert.height();
if (width > editor->maximumWidth() || (width < editor->maximumWidth() && nCount > 0)) {
float fheight = (width / (300*1.0)) + nCount;
int nheight = (width / (300*1.0)) + nCount;
float d = fheight - nheight;
if (fheight - nheight > 0 ) {
nheight ++;
}
if (d < 0.5) {
editor->setFixedSize(300, nheight * height + 28 );
} else {
editor->setFixedSize(300, nheight * height + 30 );
}
} else
{
editor->setFixedSize(width + 28, 36);
}
}
}
}
ChatFrame::ChatFrame(QWidget* parent)
: QScrollArea(parent)
{
QWidget* pWidget = new QWidget(this);
m_vLayout = new QVBoxLayout;
m_vLayout->setSpacing(10);
m_vLayout->setContentsMargins(20,20,20,20);
m_vLayout->addStretch(10);
pWidget->setLayout(m_vLayout);
this->setWidgetResizable(true);
this->setVerticalScrollBarPolicy(Qt::ScrollBarAsNeeded);
m_verticalBar = new QScrollBar;
this->setVerticalScrollBar(m_verticalBar);
this->setSizeAdjustPolicy(QAbstractScrollArea::AdjustToContents);
this->setWidget(pWidget);
}
ChatFrame::~ChatFrame()
{
}
void ChatFrame::addMessage(Message msg)
{
MessageFrame* pFrame = new MessageFrame(msg, this->widget());
int count = m_vLayout->count();
m_vLayout->insertWidget(count-1, pFrame);
m_verticalBar->setRange(0, this->widget()->height());
//所有消息列表
m_pMessages.push_back(pFrame);
m_verticalBar->setValue(m_verticalBar->maximum());
}
MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent)
{
initUI();
}
void MainWindow::initUI()
{
m_mainWidget = new QWidget;
m_vBoxLayout = new QVBoxLayout;
m_chatWidget = new ChatFrame(this);
m_chatWidget->setFrameShape(QFrame::NoFrame);
m_sendTextEdit = new QTextEdit;
m_sendTextEdit->setPlaceholderText(tr("Welcome to contact us, please describe your questions"));
m_sendTextEdit->installEventFilter(this);
m_vBoxLayout->addWidget(m_chatWidget);
m_vBoxLayout->addWidget(m_sendTextEdit);
m_vBoxLayout->setStretchFactor(m_chatWidget, 10);
m_vBoxLayout->setStretchFactor(m_sendTextEdit, 2);
m_mainWidget->setLayout(m_vBoxLayout);
setCentralWidget(m_mainWidget);
}
MainWindow::~MainWindow()
{
}
bool MainWindow::eventFilter(QObject *object, QEvent *event)
{
if(object == m_sendTextEdit)
{
if(event->type() == QEvent::KeyPress)
{
QKeyEvent* peve = dynamic_cast(event);
if((peve->modifiers() & Qt::ControlModifier) && (peve->key() == Qt::Key_Return || peve->key() == Qt::Key_Enter)) //Ctrl + Enter 换行
{
m_sendTextEdit->insertPlainText(QString(" ") += '\n');
return true;
}
if(peve->key() == Qt::Key_Return || peve->key() == Qt::Key_Enter) //回车键盘
{
sendMessage();
return true;
}
}
}
return QMainWindow::eventFilter(object, event);
}
void MainWindow::sendMessage()
{
QString msg = m_sendTextEdit->toPlainText();
// 把最后一个回车换行符删掉
while (msg.endsWith("\n")) {
msg.remove(msg.length() - 2, 2);
}
if(msg.isEmpty())
{
QMessageBox msgBox;
msgBox.setText("cannot input empty message");
msgBox.exec();
return;
}
// 清除输入框
m_sendTextEdit->clear();
Message message;
message.content = msg;
m_chatWidget->addMessage(message);
}
```cpp
#include "mainwindow.h"
#include
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
MainWindow w;
w.resize(500, 500);
w.show();
return a.exec();
}