前言
文本对象示例演示如何将 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");
}