Qt 富文本处理(24):Text Object Example【来自官档的翻译】

前言

  文本对象示例演示如何将 SVG 文件插入QText 文档。

  QTextDocument由元素层次结构组成,例如文本块和框架。文本对象描述一个或多个这些元素的结构或格式。例如,从 HTML 导入的图像使用文本对象实现。文本对象由文档的布局用于布局和呈现(绘制)文档。每个对象都知道如何绘制它们管理的元素,并计算它们的大小。

  为了能够将 SVG 图像插入文本文档中,我们创建一个文本对象,并实现该对象的绘制。然后,可以在QTextCharFormat 上设置此对象。 我们还使用文档的布局注册文本对象,使其能够绘制由文本对象控制QTextCharFormat。我们可以通过以下步骤总结该过程:

  • 实现文本对象。
  • 使用文本文档的布局注册文本对象。
  • 在QTextCharformat 上设置文本对象。
  • 将QChar::对象替换字符与该文本字符格式插入到文档中。

该示例由以下类组成:

  • SvgTextObject实现文本对象。
  • Window显示可插入 SVG 图像的QTextEdit。

SvgText 对象类定义

让我们来看看SvgTextObject的头文件:

class SvgTextObject : public QObject, public QTextObjectInterface
{
    Q_OBJECT
    Q_INTERFACES(QTextObjectInterface)

public:
    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;
};

  文本对象是实现 QTextObjectInterface 的 QObject。请注意,继承的第一个类必须是QObject,并且必须使用Q_INTERFACES使 Qt 知道你的类实现了QTextObjectInterface。

  文档布局保留存储为QObjects 的文本对象的集合,每个对象都有关联的对象类型。布局将关联对象类型的 QObject转换为QTextObject 接口。

  然后,使用intrinsicSize() 和 drawObject() 函数计算文本对象的大小并绘制它。

SvgText 对象类实现

首先,我们来看看 intrinsicSize() 函数:

QSizeF SvgTextObject::intrinsicSize(QTextDocument * /*doc*/, int /*posInDocument*/,
                                    const QTextFormat &format)
{
    QImage bufferedImage = qvariant_cast<QImage>(format.property(Window::SvgData));
    QSize size = bufferedImage.size();

    if (size.height() > 25)
        size *= 25.0 / (double) size.height();

    return QSizeF(size);
}

  intrinsicSize() 由布局调用以计算文本对象的大小。请注意,我们已经在 QImage 上绘制了SVG 图像。这是因为 SVG 渲染相当昂贵。如果我们每次用 QSvgRender 器绘制大图像,那么该示例将严重滞后。

void SvgTextObject::drawObject(QPainter *painter, const QRectF &rect,
                               QTextDocument * /*doc*/, int /*posInDocument*/,
                               const QTextFormat &format)
{
    QImage bufferedImage = qvariant_cast<QImage>(format.property(Window::SvgData));

    painter->drawImage(rect, bufferedImage);
}

在 drawObject() 中,我们使用布局提供的QPainter 绘制 SVG图像。

Window类定义

Window类是一个自包含的窗口,具有 QTextEdit,其中可以插入 SVG 图像。

class Window : public QWidget
{
    Q_OBJECT

public:
    enum { SvgTextFormat = QTextFormat::UserObject + 1 };
    enum SvgProperties { SvgData = 1 };

    Window();

private slots:
    void insertTextObject();

private:
    void setupTextObject();
    void setupGui();

private:
    QTextEdit *textEdit;
    QLabel *fileNameLabel;
    QLineEdit *fileNameLineEdit;
    QPushButton *insertTextObjectButton;
};

  insertTextObject() 槽在当前光标位置插入一个SVG图像,而setupTextObject()则创建并向文本编辑文档的布局注册SvgTextObject。

  构造函数简单地调用setupTextObject()和setupGui(),这将创建和布局窗口的小部件。

Window类实现

现在我们将仔细研究与文本对象相关的函数,首先是setupTextObject()函数。

void Window::setupTextObject()
{
    QObject *svgInterface = new SvgTextObject;
    svgInterface->setParent(this);
    textEdit->document()->documentLayout()->registerHandler(SvgTextFormat, svgInterface);
}

SvgTextFormat的值是自定义对象类型的数值。它用于通过文档布局标识对象类型。
注意,我们只创建了一个SvgTextObject实例;它将用于所有QTextCharFormat的SvgTextFormat对象类型。

让我们继续看insertTextObject()函数:

void Window::insertTextObject()
{
    QString fileName = fileNameLineEdit->text();
    QFile file(fileName);
    if (!file.open(QIODevice::ReadOnly)) {
        QMessageBox::warning(this, tr("Error Opening File"),
                             tr("Could not open '%1'").arg(fileName));
    }

    QByteArray svgData = file.readAll();

首先,打开.svg文件,并将其内容读入svgData数组。

    QTextCharFormat svgCharFormat;
    svgCharFormat.setObjectType(SvgTextFormat);
    QSvgRenderer renderer(svgData);

    QImage svgBufferImage(renderer.defaultSize(), QImage::Format_ARGB32);
    QPainter painter(&svgBufferImage);
    renderer.render(&painter, svgBufferImage.rect());

    svgCharFormat.setProperty(SvgData, svgBufferImage);

    QTextCursor cursor = textEdit->textCursor();
    cursor.insertText(QString(QChar::ObjectReplacementCharacter), svgCharFormat);
    textEdit->setTextCursor(cursor);
}

  为了加快速度,我们在QImage中缓冲SVG图像。我们使用setProperty( )将QImage存储在QTextCharFormat 中。我们可以稍后使用property()检索它。

  我们插入字符格式的标准方式 - 使用QTextCursor。请注意,我们使用特殊的QChar象替换字符。

void Window::setupGui()
{
    fileNameLabel = new QLabel(tr("Svg File Name:"));
    fileNameLineEdit = new QLineEdit;
    insertTextObjectButton = new QPushButton(tr("Insert Image"));

    fileNameLineEdit->setText(":/heart.svg");
    connect(insertTextObjectButton, SIGNAL(clicked()),
            this, SLOT(insertTextObject()));

    QHBoxLayout *bottomLayout = new QHBoxLayout;
    bottomLayout->addWidget(fileNameLabel);
    bottomLayout->addWidget(fileNameLineEdit);
    bottomLayout->addWidget(insertTextObjectButton);

    textEdit = new QTextEdit;

    QVBoxLayout *mainLayout = new QVBoxLayout;
    mainLayout->addWidget(textEdit);
    mainLayout->addLayout(bottomLayout);

    setLayout(mainLayout);
}
Window::Window(QWidget *parent)
    : QWidget(parent)
{
    setupGui();
    setupTextObject();

    setWindowTitle("Text Object Example");
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值