Qt - Как посчитать и измерить строки в QTextDocument? - PullRequest
0 голосов
/ 03 апреля 2020

В одном из моих проектов я создал 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.

Изображения являются изображениями SVG, полученными из ресурсов qml.

Чтобы выполнить несколько операций во время рисования текста, мне нужно знать, сколько линий будет нарисовано после применения переноса слов, и высота любой строки в завернутом в слово тексте.

Я попытался выполнить поиск в функциях, предоставляемых текстовым документом, а также в функциях, предоставленных в 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. Как я могу сосчитать строки, содержащиеся в моем завернутый в слово документ
  2. Как измерить высоту строки в моем завернутом слове документ
  3. Не работает ли функция текстового документа из-за html формат? Если да, как мне поступить, чтобы достичь своих целей в таком контексте?

ПРИМЕЧАНИЕ Я знаю, как измерить всю высоту текста. Однако, поскольку высота каждой строки может быть разной, я не могу просто разделить всю высоту текста на строки, поэтому для меня это неприемлемое решение.

1 Ответ

0 голосов
/ 06 апреля 2020

Я наконец нашел способ решить мою проблему. Текстовый документ не может использоваться непосредственно для измерения отдельных линий, вместо этого следует использовать макет, как объясняется в следующем посте: 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();
}
//---------------------------------------------------------------------------
...