首页 > 解决方案 > Qt - 如何计算和测量 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 中提供的功能。我尝试了几种方法,例如用光标遍历字符并计算行数,或计算块中的每个片段。不幸的是,它们都没有奏效:所有功能总是算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;

我无法弄清楚我做错了什么,以及为什么我所有的方法都失败了。

所以我的问题是:

  1. 如何计算我的word 包装文档中包含的行数
  2. 如何测量我的word 包装文档中的行高
  3. 文本文档功能是否因为 html 格式而失败?如果是,在这种情况下我应该如何实现我的目标?

注意我知道如何测量整个文本的高度。但是,由于每个行高可能不同,我不能只将整个文本高度除以行,所以这对我来说不是一个可接受的解决方案。

标签: qtcountlinemeasureqtextdocument

解决方案


我终于找到了解决我的问题的方法。文本文档不能直接用于测量单个行,布局应该用于此目的,如以下帖子所述: 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();
}
//---------------------------------------------------------------------------

推荐阅读