QTextEdit将多个字符作为一个整体,不可单独修改

考虑一个问题,QTextEdit如何实现类似微信和QQ聊天输入框中的“@xxx”效果,其内容作为一个整体,以突出颜色显示,并且不可以单独编辑修改,只能整体删除修改。

突出颜色显示有很多方式可以实现,例如

  • 通过setTextColor接口,此接口可以设置当前字体颜色为指定颜色
//保存当前颜色
QColor _color = this->textColor();
//设置为红色
this->setTextColor(Qt::red);
//添加文字
this->append("hello world");
//恢复颜色
this->setTextColor(_color);
  • 通过html格式实现
this->append("<font color=\"#FF0000\">红色字体</font> ");
  • 通过QTextCharFormat实现
auto cursor = this->textCursor();
//备份格式
 auto backFormat = cursor.charFormat();
 //设置字体
 auto _font_size = this->font().pointSize();
 //构建格式
 QTextCharFormat _format;
 //设置文本颜色
 _format.setForeground(Qt::red);
 cursor.insertText(QString(QChar::ObjectReplacementCharacter),_format);
 //恢复默认格式
 this->setCurrentCharFormat(backFormat);

颜色搞定了,如何将指定的字符串设为整体呢?
通过面向百度编程和查阅文档(主要是面向百度编程,哈哈)找到一种方法。
众所周知,QTextEdit中的内容是有QTextDocument类实现渲染的,而QTextDocument的布局方式是由QAbstractTextDocumentLayout实现的,可以通过QAbstractTextDocumentLayout *QTextDocument::documentLayout()接口获取。而在QAbstractTextDocumentLayout类中提供了
void registerHandler(int objectType, QObject *component)接口可以注册自定义的Handler实现自定义绘制。因此可以通过此方式实现将多个文本作为整体。

先看效果
在这里插入图片描述
继承QTextObjectInterface实现intrinsicSizedrawObject

enum TextFormatRole
{
    //字体大小
    Format_FontSize = QTextFormat::UserProperty + 1,
    //文本
    Format_Text
};
class TextEditHander : public QObject,QTextObjectInterface
{
    Q_OBJECT
    Q_INTERFACES(QTextObjectInterface)
public:
    TextEditHander(QObject* parent = nullptr);
    ~TextEditHander();
    //计算绘制区域
    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;

};
TextEditHander::TextEditHander(QObject *parent):QObject(parent)
{

}

TextEditHander::~TextEditHander()
{

}

//计算绘制区域
QSizeF TextEditHander::intrinsicSize(QTextDocument *doc, int posInDocument,
                                     const QTextFormat &format)
{
    //获取字体大小
    int font_size = format.property(Format_FontSize).toInt();
    QString text = format.property(TextFormatRole::Format_Text).toString();

    auto _font = doc->defaultFont();
    _font.setPointSize(font_size);
    QFontMetrics _metrics(_font);
    int textWidth = _metrics.horizontalAdvance(text);

    return QSizeF(textWidth,_metrics.height());
}

//绘制
void TextEditHander::drawObject(QPainter *painter, const QRectF &rect,
                                QTextDocument *doc, int posInDocument, const QTextFormat &format)
{
    Q_UNUSED(doc);
    Q_UNUSED(posInDocument);
    QString text = format.property(Format_Text).toString();
    int font_size = format.property(Format_FontSize).toInt();

    //调整rect
//    QRectF _drawRect = rect.adjusted(0,1,0,-1);
    QRectF _drawRect = rect;

    //绘制
    painter->save();

    //绘制背景
    painter->fillRect(_drawRect,format.background());
    //绘制文字
    auto _font = doc->defaultFont();
    _font.setPointSize(font_size);
    painter->setFont(_font);
    painter->setPen(format.foreground().color());
    painter->drawText(_drawRect,Qt::AlignBaseline,text);

    painter->restore();
}

继承QTextEdit

class TextEdit : public QTextEdit
{
    Q_OBJECT
public:
    explicit TextEdit(QWidget *parent = nullptr);
    virtual ~TextEdit() = default;
protected slots:
    //插入标签
    void slot_addText();
};
TextEdit::TextEdit(QWidget *parent)
    : QTextEdit{parent}
{
    //注册handler
    auto handler = new TextEditHander(this);
    this->document()->documentLayout()->registerHandler(QTextFormat::UserObject+1,handler);

    QFont _font = this->font();
    _font.setPointSize(12);
    this->setFont(_font);

    //创建右键菜单
    QAction *act = new QAction("插入标签",this);
    connect(act,&QAction::triggered,this,&TextEdit::slot_addText);
    this->addAction(act);
    this->setContextMenuPolicy(Qt::ActionsContextMenu);
}

void TextEdit::slot_addText()
{
    auto cursor = this->textCursor();
    //备份格式
    auto backFormat = cursor.charFormat();
    //设置字体
    auto _font_size = this->font().pointSize();
    //构建格式
    QTextCharFormat _format;
    //设置格式使用自定义的Hander渲染,这步很重要
    _format.setObjectType(QTextFormat::UserObject + 1);
    //设置需要绘制的文本
    _format.setProperty(TextFormatRole::Format_Text,"${123}");
    //设置字体大小
    _format.setProperty(TextFormatRole::Format_FontSize,_font_size);
    //设置前景色
    _format.setForeground(Qt::black);
    //设置背景色
    _format.setBackground(Qt::lightGray);

    cursor.insertText(QString(QChar::ObjectReplacementCharacter),_format);

    //恢复默认格式
    this->setCurrentCharFormat(backFormat);
    //添加一个空格
    this->textCursor().insertText(" ");

}

  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值