1. 程式人生 > 其它 >一種用QT實現即時通訊軟體表情傳送與接收的思路

一種用QT實現即時通訊軟體表情傳送與接收的思路

技術標籤:QT前端qtc++

一種用QT實現即時通訊軟體表情傳送與接收的思路

最近需要使用QT為專案新增一個表情包傳送與接受的功能,雖然之前知道表情傳送與接收顯示的一個基本原理,但是其中涉及到例如表情包插入到QTextEdit如何顯示,如何保證從文字框傳送出去的是表情編碼在顯示的時候卻是一個表情圖片等細節問題。一開始是在網上搜尋相關的部落格,但是搜尋了很多基本只是涉及到使用QT開發一個最基本的表情包面板的教程,涉及到詳細闡述表情的傳送與接收這樣的互動過程的文章我基本沒有看到,即使有也不是用QT去做的。特此,在這裡記錄以下自己實現這個功能的一個簡單的思路,目前雖然實現了一個基本功能,但是還是有很多值得改進的地方,如果大家有更好的方法,歡迎多多評論

  1. 表情面板的繪製
    因為目前大部分的表情面板都是以行列形式存在的,所以我自然就想到了以一個QTableWidget來存放表情,然後在一個單元格里去建立一個QLabel來載入表情圖片展示(不過這裡涉及到一個記憶體分配的問題,因為目前我的表情比較少,只有56個,建立56個label我親自測過大概會佔用0.5M的記憶體,如果以後有上百個表情,這樣的記憶體消耗是一個不小的開銷,這是一個後續要優化的地方,可能會以繪圖的方式優化).剩下的就是關於滑鼠懸浮在表情的上面需要展現的一些效果,如果你有動態圖的話,那當然可以在滑鼠懸浮在上面的時候展現動態表情,具體的實現可以看下面的程式碼

.h檔案

class CAbstractEmojiWgt
: public QTableWidget { Q_OBJECT public: CAbstractEmojiWgt(QWidget *parent); virtual ~CAbstractEmojiWgt(); virtual int setRowCountAndColumnCount(int totalCount,int columnCount=10); private: virtual void addEmoji() {}; virtual void initStyle() {}; virtual void initConnect(){}; }; class CBaseEmojiWgt
: public CAbstractEmojiWgt { Q_OBJECT public: CBaseEmojiWgt(QWidget *parent); ~CBaseEmojiWgt(); Q_SIGNALS: void insertEmoji(const QString &emojicode); private Q_SLOTS: void oncellClicked(int row,int column); private: virtual void addEmoji()override; virtual void initStyle() override; virtual void initConnect()override; private: };

.cpp檔案

#include "cbaseemojiwgt.h"
#include<QHeaderView>
#include<QLabel>
#include<QDebug>
CBaseEmojiWgt::CBaseEmojiWgt(QWidget *parent)
	: CAbstractEmojiWgt(parent)
{
	setRowCountAndColumnCount(56, 10);
	setMouseTracking(true);
	addEmoji();
	initStyle();
	initConnect();
}

CBaseEmojiWgt::~CBaseEmojiWgt()
{
	clearContents();
}

void CBaseEmojiWgt::addEmoji()
{
	if (rowCount() == 0 || columnCount() == 0) {
		return;
	}
	int columncount = columnCount();
	int emojiIndex = 0;
	int rowIndex = 0;
	int columnIndex = 0;
	//遍歷map
	//code2url是一個存放表情編碼和對應的圖片url的QMap,表情編碼是預先和同事協商的
	//for example: [happy]:":/emoji/happy.png"
	auto it = code2url.begin();               
	while (it != code2url.end()) {
		rowIndex = emojiIndex / columncount;
		columnIndex = emojiIndex % columncount;
		QLabel * label = new QLabel(this);
		label->setPixmap(QPixmap(it.value()));
		label->setScaledContents(true);
		label->setAlignment(Qt::AlignCenter);
		label->setToolTip(it.key());
		setCellWidget(rowIndex, columnIndex, label);
		++emojiIndex;
		++it;
	} 
}

void CBaseEmojiWgt::initStyle()
{
	setFixedSize(250,160);
	verticalHeader()->setVisible(false);
	horizontalHeader()->setVisible(false);
	horizontalHeader()->setSectionResizeMode(QHeaderView::Stretch);
	verticalHeader()->setSectionResizeMode(QHeaderView::Stretch);
	setShowGrid(false);
	setObjectName("BaseEmojiWgt");
	setStyleSheet("QLabel:hover{border:1px solid #caced1;}"\
		"QTableWidget#BaseEmojiWgt{border:1px solid #D8DCE0;}"\
	    "QTableWidget::item:selected{background-color:white;outline:0px;}");
}


void CBaseEmojiWgt::initConnect()
{
	connect(this, &CBaseEmojiWgt::cellClicked, this, &CBaseEmojiWgt::oncellClicked);
}

void CBaseEmojiWgt::oncellClicked(int row,int column)
{
	if (row<0 || column<0 || row>rowCount() || column>columnCount()){
		return;
	}
	QLabel * label = dynamic_cast<QLabel *>(cellWidget(row, column));
	if (label != Q_NULLPTR){
		label->setStyleSheet("background-color:white");
		hide();
		emit insertEmoji(label->toolTip());
	}
}

面板的實現效果圖
面版實現效果

  1. 表情的插入
    上述的表情面板在接收到點選之後,會發送一個插入表情的訊號 inertEomji(const QString &emoji),建立了一個專門處理表情相關事務的類,在接收到訊號之後會觸發以下方法,這裡我是選擇直接插入html的方式,當然你也可以使用cursor->insertimage等其他方法(這部分可以參考QT官方文件的QTextEdit,QTextCursor和QTextDocument部分,裡面寫了很多關於富文字使用的高階方法
void  DealEmoji::insertEmojiIntoTextEdit(const QString &emojicode, QTextEdit * textedt)
{
	if (textedt == Q_NULLPTR){
		return;
	}
	QString emojiurl = getEmojiUrl(emojicode);
	QTextDocument * temp=Q_NULLPTR;
	if (emojiurl != QString()){
		_vectcode.push_back(emojicode);        //儲存了你選擇插入的表情的編碼
		QTextCursor cursor = textedt->textCursor();
		cursor.insertHtml(QString("<img src=\"%1\" width=\"24\" height=\"24\" />").arg(emojiurl));
	    textedt->setTextCursor(cursor);
	    textedt->setFocus();
	}
}

3. 表情包的傳送
這一部分需要將你的textEdit中文字與表情相混合的內容傳送出去,但是注意我們插入的是標籤,但是在傳送的時候我們需要將標籤全部轉換成表情的編碼傳送出去,這樣對方在接收到含有表情編碼的文字的時候可以檢測是否含有表情編碼然後再將對應的表情顯示出來

void DealEmoji::transFromUrlToCode(QString& messagehtml)
{
	if (messagehtml.isEmpty()) {
		return;
	}
	if (!_vectcode.isEmpty()) {
		for (auto& code : _vectcode) {
			messagehtml.replace(QString("<img src=\"%1\" width=\"24\" height=\"24\" />").arg(code2url[code]), code);
		}
	}
	return;
}

  1. 表情包接收與展示
    在對方接收到一個含有表情的資訊的時候,我們首先需要用正則表示式來找出資訊中所有的表情的表情編碼,然後將其全部替換為表籤,通過富文字的方式將表情以圖片的形式在訊息label展現出來
void DealEmoji::transFromCodeToUrl(QString  &message)
{
	if (message.isEmpty()) {
		return;
	}
	int pos = 0;
	//_rx為正則表示式儲存了所有的表情編碼
	while ((pos = _rx.indexIn(message, pos)) != -1) {
		QString code = _rx.cap(1);
		_vectcode.push_back(code);
		message = message.replace(code, QString("<img src=\"%1\" width=\"24\" height=\"24\" />").arg(code2url[code]));
		pos += _rx.matchedLength();
	}
	return;
}

實現效果:
在這裡插入圖片描述

##總結:以上就是表情的傳送與接收轉換的一個基本思路,當然後面還會涉及到關於表情的複製黏貼,表情的轉發等細節問題,但是基本思路就是表情編碼與對應的圖片url的互相替換,如果大家有什麼更好的思路可以在下面評論,謝謝