❝文本对象示例演示如何将SVG文件插入QTextDocument中。❞
QTextDocument包括元素,如文本块和帧的层次结构的。文本对象描述了一个或多个这些元素的结构或格式。例如,从HTML导入的图像是使用文本对象实现的。文档的布局使用文本对象来布局和渲染(绘制)文档。每个对象都知道如何绘制它们控制的元素,并计算其大小。
为了能够在文本文档中插入SVG图像,我们创建了一个文本对象,并对该对象进行绘画。然后可以在QTextCharFormat上设置此对象。我们还将文本对象注册到文档的布局中,从而使其能够绘制受文本对象控制的QTextCharFormat。我们可以通过以下步骤总结该过程:
QChar::ObjectReplacementCharacter
插入文档中。该示例包含以下类:
让我们看一下的头文件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。
文档布局保留了存储为QObject的文本对象的集合,每个文本对象都具有关联的对象类型。布局将关联对象类型的QObject强制转换为QTextObjectInterface。
所述intrinsicSize和drawObject函数然后用来计算文本对象的大小和绘制。
我们首先看一下internalSize函数:
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渲染非常耗时。如果我们每次都使用QSvgRenderer绘制大型图像,该示例将严重滞后卡顿。
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」类是具有一个独立的窗口的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()创建和布局窗口。
现在,从setupTextObject()开始,我们将仔细研究与文本对象相关的功能。
void Window::setupTextObject()
{
QObject *svgInterface = new SvgTextObject;
svgInterface->setParent(this);
textEdit->document()->documentLayout()->registerHandler(SvgTextFormat, svgInterface);
}
SvgTextFormat的值是我们的对象类型的数量。它用于通过文档布局识别对象类型。
请注意,我们仅创建一个SvgTextObject实例。它将用于具有对象类型的所有QTextCharFormatSvgTextFormat。
让我们看看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);
}
为了加快速度,我们将SVG图像缓存在QImage中。我们使用setProperty()将QImage存储在QTextCharFormat中。我们稍后可以使用property()获取它。
我们使用QTextCursor以标准方式插入字符格式。注意,我们使用特殊的QChar对象替换字符(https://doc.qt.io/qt-5/qchar.html#SpecialCharacter-enum)。
C:\Qt\{你的Qt版本}\Examples\{你的Qt版本}\svg\richtext\textobject
https://doc.qt.io/qt-5/qtsvg-richtext-textobject-example.html