📒博客首页:何名取 的个人主页 - 文章 - 掘金 (juejin.cn)
🎉欢迎关注🔎点赞👍收藏⭐️留言📝
❤️期待一起交流!
🙏作者水平很有限,如果发现错误,求告知,多谢!
🌺有问题可私信交流!!!
QTextObject
前言
之前的文章中实现了群聊@的功能,对比微信的群聊艾特功能发现还是有一些差异,微信的艾特选择群成员后在输入框中插入的是@xxx的一个整体文字块,不能修改,删除时也会将整个文字块进行删除。本节则实现将多个文字合成整体插入输入框中,做出类似下图微信里的效果。
富文本类简介
在进行代码实现之前,首先来简单了解一下QTextEidt这个控件。QTextEidt是一个富文本编辑器,已经包含了QTextCursor(文字光标,用来操作QTextDocument)和QTextDocument(保存格式文本)。
因此,我们需要先使用QTextDocument类相关的子类来自定义一个文字块对象,然后使用QTextCursor类将这个自定义的文本对象插入到QTextEdit输入框中即可。
自定义文本对象类
QTextObjectInterface类允许在QTextDocuments中绘制自定义文本对象。
具体操作如下:
- 选择一个对象类型objectType。objectType是一个大于或等于QTextFormat::UserObject的整数。
- 创建一个QTextCharFormat对象,并使用setObjectType()函数将对象类型设置为所选类型。
- 通过继承实现QTextObjectInterface类。
- 使用QTextObjectInterface子类的实例调用QAbstractTextDocumentLayout::registerHandler()来注册你的对象类型。
- 将QChar::ObjectReplacementCharacter与前面提到的所选对象类型的QTextCharFormat插入到文档中。正如前面提到的,QTextObjectInterface intrinsicSize()和drawObject()函数将在遇到替换字符时以QTextFormat作为参数调用。
以下是通过继承实现的艾特文本块对象:
#ifndef ATMEMBERTEXTOBJECT_H
#define ATMEMBERTEXTOBJECT_H
#include <QTextObjectInterface>
#include <QFontMetrics>
#include <QPainter>
QT_BEGIN_NAMESPACE
class QTextDocument;
class QTextFormat;
class QPainter;
class QRectF;
class QSizeF;
QT_END_NAMESPACE
enum { AtTextFormat = QTextFormat::UserObject + 1 };
enum AtTextProperties { AtData = 1 };
class AtMemberTextObject : public QObject, public QTextObjectInterface
{
Q_OBJECT
Q_INTERFACES(QTextObjectInterface)
public:
explicit AtMemberTextObject();
QSizeF intrinsicSize(QTextDocument *doc, int posInDocument,
const QTextFormat &format) override;
void drawObject(QPainter *painter, const QRectF &rect, QTextDocument *doc,
int posInDocument, const QTextFormat &format) override;
private:
QFontMetrics *m_pmf;
QFont m_font;
};
#endif // ATMEMBERTEXTOBJECT_H
#include "atmembertextobject.h"
AtMemberTextObject::AtMemberTextObject()
{
m_font.setFamily("微软雅黑");
m_font.setPointSize(16);
m_pmf = new QFontMetrics(m_font);
// qDebug()<<"AtMemberTextObject-height:"<<m_pmf->height();//高度
// qDebug()<<"AtMemberTextObject-ascent:"<<m_pmf->ascent();//基线以上高度
// qDebug()<<"AtMemberTextObject-descent:"<<m_pmf->descent();//基线以下高度
// qDebug()<<"AtMemberTextObject-leading:"<<m_pmf->leading();//行距
// qDebug()<<"AtMemberTextObject-lineSpacing:"<<m_pmf->lineSpacing();//行高
}
QSizeF AtMemberTextObject::intrinsicSize(QTextDocument *doc, int posInDocument, const QTextFormat &format)
{
Q_UNUSED(doc)
Q_UNUSED(posInDocument)
QString txt = qvariant_cast<QString>(format.property(AtData));
return QSizeF(m_pmf->size(Qt::AlignCenter,txt).width(),
m_pmf->height());
}
void AtMemberTextObject::drawObject(QPainter *painter, const QRectF &rect, QTextDocument *doc, int posInDocument, const QTextFormat &format)
{
Q_UNUSED(doc)
Q_UNUSED(posInDocument)
QString txt = qvariant_cast<QString>(format.property(AtData));
painter->fillRect(rect,QBrush(QColor("#00ffff")));
painter->drawText(rect,QTextCharFormat::AlignBaseline,txt);
}
接下来是在输入框QTextEdit包含的QTextDocument中进行注册对象类型:
#include "mainwindow.h"
#include "ui_mainwindow.h"
#include <QTextDocument>
#include <QAbstractTextDocumentLayout>
#include <QTextFrame>
#include <QTextBlock>
#include "atmembertextobject.h"
MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent)
, ui(new Ui::MainWindow)
{
ui->setupUi(this);
AtMemberTextObject *atObj = new AtMemberTextObject;
ui->textEdit->document()->documentLayout()->registerHandler(AtTextFormat,atObj);
}
MainWindow::~MainWindow()
{
delete ui;
}
void MainWindow::on_pushButton_clicked()
{
QTextDocument* doc = ui->textEdit->document();
QTextFrame *root_frame = doc->rootFrame();
QTextFrameFormat root_frame_format = root_frame->frameFormat();//创建框架格式
QTextCharFormat textcharFormat;
textcharFormat.setVerticalAlignment(QTextCharFormat::AlignBottom);
textcharFormat.setObjectType(AtTextFormat);
textcharFormat.setProperty(AtData,QVariant("@小路"));
ui->textEdit->mergeCurrentCharFormat(textcharFormat);
QTextCursor cursor = ui->textEdit->textCursor();
cursor.movePosition(QTextCursor::End);
cursor.insertText(QString(QChar::ObjectReplacementCharacter),textcharFormat);
cursor.insertText("关注我");
}
需要注意的是,在插入对象之前可以选择将文本放置于Block框架底部,不然会造成文本对象与其他正常文字不平齐的现象
textcharFormat.setVerticalAlignment(QTextCharFormat::AlignBottom);
实现效果如下: