Qt - 如何计算和测量 QTextDocument 中的行数?
Qt - How to count and measure the lines in a QTextDocument?
在我的一个项目中,我创建了一个 QTextDocument,它拥有我需要绘制的文本。文本是一个字包裹 HTML 格式的文本,它应该被绘制在一个我知道宽度的矩形区域中。其内容也不会超过一个段落。
文本文档创建如下:
// create and configure the text document to measure
QTextDocument textDoc;
textDoc.setHtml(text);
textDoc.setDocumentMargin(m_TextMargin);
textDoc.setDefaultFont(m_Font);
textDoc.setDefaultTextOption(m_TextOption);
textDoc.setTextWidth(m_Background.GetMessageWidth(size().width()));
这是我要绘制的示例文本:
Ceci est un texte <img src=\"Resources/1f601.svg\" width=\"24\" height=\"24\"> avec <img src=\"Resources/1f970.svg\" width=\"24\" height=\"24\"> une <img src=\"Resources/1f914.svg\" width=\"24\" height=\"24\"> dizaine <img src=\"Resources/1f469-1f3fe.svg\" width=\"24\" height=\"24\"> de <img src=\"Resources/1f3a8.svg\" width=\"24\" height=\"24\"> mots. Pour voir comment la vue réagit.
图片是从qml资源中获取的SVG图片。
为了在绘制文本时执行多项操作,我需要知道应用自动换行后将绘制多少行,以及自动换行文本中任何行的高度。
我试着在文本文档提供的函数中搜索,以及QTextBLock、QTextFragment和QTextCursor中提供的函数。我尝试了几种方法,比如用光标遍历字符并计算行数,或者计算块中的每个片段。不幸的是,其中 none 个有效:所有函数总是计算 1 行,或者只是失败。
以下是我已经尝试过但没有成功的一些代码示例:
// FAILS - always return 1
int lineCount = textDoc.lineCount()
// FAILS - always return 1
int lineCount = textDoc.blockCount()
// FAILS - return the whole text height, not a particular line height at index
int lineHeight = int(textDoc.documentLayout()->blockBoundingRect(textDoc.findBlockByNumber(lineNb)).height());
// get the paragraph (there is only 1 paragraph in the item text document
QTextBlock textBlock = textDoc.findBlockByLineNumber(lineNb);
int blockCount = 0;
for (QTextBlock::iterator it = textBlock.begin(); it != textBlock.end(); ++it)
{
// FAILS - fragments aren't divided by line, e.g an image will generate a fragment
QString blockText = it.fragment().text();
++blockCount;
}
return blockCount;
QTextCursor cursor(&textDoc);
int lineCount = 0;
cursor.movePosition(QTextCursor::Start);
// FAILS - movePosition() always return false
while (cursor.movePosition(QTextCursor::Down))
++lineCount;
我不知道我做错了什么,也不知道为什么我的所有方法都失败了。
所以我的问题是:
- 如何计算我的 word wrapped 文档
中包含的行数
- 如何测量我的 word wrapped 文档
中一行的高度
- 文本文档功能是否因为html格式而失败?如果是,在这种情况下我应该怎么做才能达到我的目标?
注意 我知道如何测量整个文本的高度。但是,由于每个行高可能不同,我不能只将整个文本高度除以行,所以这对我来说不是一个可以接受的解决方案。
我终于找到了解决问题的方法。文本文档不能直接用于测量单行,布局应用于此目的,如下所述post:
https://forum.qt.io/topic/113275/how-to-count-and-measure-the-lines-in-a-qtextdocument
所以下面的代码就是解决方案:
//---------------------------------------------------------------------------
int getLineCount(const QString& text) const
{
// create and configure the text document to measure
QTextDocument textDoc;
textDoc.setHtml(text);
textDoc.setDocumentMargin(m_TextMargin);
textDoc.setDefaultFont(m_Font);
textDoc.setDefaultTextOption(m_TextOption);
textDoc.setTextWidth(m_Background.GetMessageWidth(size().width()));
// this line is required to force the document to create the layout, which will then be used
//to count the lines
textDoc.documentLayout();
// the document should at least contain one block
if (textDoc.blockCount() < 1)
return -1;
int lineCount = 0;
// iterate through document paragraphs (NOTE normally the message item should contain only 1 paragraph
for (QTextBlock it = textDoc.begin(); it != textDoc.end(); it = it.next())
{
// get the block layout
QTextLayout* pBlockLayout = it.layout();
// should always exist, otherwise error
if (!pBlockLayout)
return -1;
// count the block lines
lineCount += pBlockLayout->lineCount();
}
return lineCount;
}
//---------------------------------------------------------------------------
int measureLineHeight(const QString& text, int lineNb, int blockNb) const
{
// create and configure the text document to measure
QTextDocument textDoc;
textDoc.setHtml(text);
textDoc.setDocumentMargin(m_TextMargin);
textDoc.setDefaultFont(m_Font);
textDoc.setDefaultTextOption(m_TextOption);
textDoc.setTextWidth(m_Background.GetMessageWidth(size().width()));
// this line is required to force the document to create the layout, which will then be used
//to count the lines
textDoc.documentLayout();
// check if block number is out of bounds
if (blockNb >= textDoc.blockCount())
return -1;
// get text block and its layout
QTextBlock textBlock = textDoc.findBlockByNumber(blockNb);
QTextLayout* pLayout = textBlock.layout();
if (!pLayout)
return -1;
// check if line number is out of bounds
if (lineNb >= pLayout->lineCount())
return -1;
// get the line to measure
QTextLine textLine = pLayout->lineAt(lineNb);
return textLine.height();
}
//---------------------------------------------------------------------------
在我的一个项目中,我创建了一个 QTextDocument,它拥有我需要绘制的文本。文本是一个字包裹 HTML 格式的文本,它应该被绘制在一个我知道宽度的矩形区域中。其内容也不会超过一个段落。
文本文档创建如下:
// create and configure the text document to measure
QTextDocument textDoc;
textDoc.setHtml(text);
textDoc.setDocumentMargin(m_TextMargin);
textDoc.setDefaultFont(m_Font);
textDoc.setDefaultTextOption(m_TextOption);
textDoc.setTextWidth(m_Background.GetMessageWidth(size().width()));
这是我要绘制的示例文本:
Ceci est un texte <img src=\"Resources/1f601.svg\" width=\"24\" height=\"24\"> avec <img src=\"Resources/1f970.svg\" width=\"24\" height=\"24\"> une <img src=\"Resources/1f914.svg\" width=\"24\" height=\"24\"> dizaine <img src=\"Resources/1f469-1f3fe.svg\" width=\"24\" height=\"24\"> de <img src=\"Resources/1f3a8.svg\" width=\"24\" height=\"24\"> mots. Pour voir comment la vue réagit.
图片是从qml资源中获取的SVG图片。
为了在绘制文本时执行多项操作,我需要知道应用自动换行后将绘制多少行,以及自动换行文本中任何行的高度。
我试着在文本文档提供的函数中搜索,以及QTextBLock、QTextFragment和QTextCursor中提供的函数。我尝试了几种方法,比如用光标遍历字符并计算行数,或者计算块中的每个片段。不幸的是,其中 none 个有效:所有函数总是计算 1 行,或者只是失败。
以下是我已经尝试过但没有成功的一些代码示例:
// FAILS - always return 1
int lineCount = textDoc.lineCount()
// FAILS - always return 1
int lineCount = textDoc.blockCount()
// FAILS - return the whole text height, not a particular line height at index
int lineHeight = int(textDoc.documentLayout()->blockBoundingRect(textDoc.findBlockByNumber(lineNb)).height());
// get the paragraph (there is only 1 paragraph in the item text document
QTextBlock textBlock = textDoc.findBlockByLineNumber(lineNb);
int blockCount = 0;
for (QTextBlock::iterator it = textBlock.begin(); it != textBlock.end(); ++it)
{
// FAILS - fragments aren't divided by line, e.g an image will generate a fragment
QString blockText = it.fragment().text();
++blockCount;
}
return blockCount;
QTextCursor cursor(&textDoc);
int lineCount = 0;
cursor.movePosition(QTextCursor::Start);
// FAILS - movePosition() always return false
while (cursor.movePosition(QTextCursor::Down))
++lineCount;
我不知道我做错了什么,也不知道为什么我的所有方法都失败了。
所以我的问题是:
- 如何计算我的 word wrapped 文档 中包含的行数
- 如何测量我的 word wrapped 文档 中一行的高度
- 文本文档功能是否因为html格式而失败?如果是,在这种情况下我应该怎么做才能达到我的目标?
注意 我知道如何测量整个文本的高度。但是,由于每个行高可能不同,我不能只将整个文本高度除以行,所以这对我来说不是一个可以接受的解决方案。
我终于找到了解决问题的方法。文本文档不能直接用于测量单行,布局应用于此目的,如下所述post: https://forum.qt.io/topic/113275/how-to-count-and-measure-the-lines-in-a-qtextdocument
所以下面的代码就是解决方案:
//---------------------------------------------------------------------------
int getLineCount(const QString& text) const
{
// create and configure the text document to measure
QTextDocument textDoc;
textDoc.setHtml(text);
textDoc.setDocumentMargin(m_TextMargin);
textDoc.setDefaultFont(m_Font);
textDoc.setDefaultTextOption(m_TextOption);
textDoc.setTextWidth(m_Background.GetMessageWidth(size().width()));
// this line is required to force the document to create the layout, which will then be used
//to count the lines
textDoc.documentLayout();
// the document should at least contain one block
if (textDoc.blockCount() < 1)
return -1;
int lineCount = 0;
// iterate through document paragraphs (NOTE normally the message item should contain only 1 paragraph
for (QTextBlock it = textDoc.begin(); it != textDoc.end(); it = it.next())
{
// get the block layout
QTextLayout* pBlockLayout = it.layout();
// should always exist, otherwise error
if (!pBlockLayout)
return -1;
// count the block lines
lineCount += pBlockLayout->lineCount();
}
return lineCount;
}
//---------------------------------------------------------------------------
int measureLineHeight(const QString& text, int lineNb, int blockNb) const
{
// create and configure the text document to measure
QTextDocument textDoc;
textDoc.setHtml(text);
textDoc.setDocumentMargin(m_TextMargin);
textDoc.setDefaultFont(m_Font);
textDoc.setDefaultTextOption(m_TextOption);
textDoc.setTextWidth(m_Background.GetMessageWidth(size().width()));
// this line is required to force the document to create the layout, which will then be used
//to count the lines
textDoc.documentLayout();
// check if block number is out of bounds
if (blockNb >= textDoc.blockCount())
return -1;
// get text block and its layout
QTextBlock textBlock = textDoc.findBlockByNumber(blockNb);
QTextLayout* pLayout = textBlock.layout();
if (!pLayout)
return -1;
// check if line number is out of bounds
if (lineNb >= pLayout->lineCount())
return -1;
// get the line to measure
QTextLine textLine = pLayout->lineAt(lineNb);
return textLine.height();
}
//---------------------------------------------------------------------------