Введение

Работа с текстом в Qt — это мощный, но иногда сложный процесс. Когда дело доходит до отрисовки выделения текста в QTextDocument, многие разработчики сталкиваются с проблемами. Часто предлагаемые решения, такие как изменение QTextCharFormat, не всегда подходят, особенно если нужно сохранить исходное форматирование текста. В этой статье я расскажу о правильном способе отрисовки выделения с использованием QAbstractTextDocumentLayout::PaintContext.

Почему стандартные методы не всегда работают

Обычно для выделения текста в QTextDocument используют QTextCursor и QTextCharFormat. Например:

QTextCursor cursor(document);
cursor.movePosition(QTextCursor::Start);
cursor.movePosition(QTextCursor::End, QTextCursor::KeepAnchor);

QTextCharFormat format;
format.setBackground(Qt::yellow);
cursor.mergeCharFormat(format);

Этот метод изменяет форматирование текста, что не всегда удобно. Например, если вам нужно временно подсветить текст, а затем вернуть его в исходное состояние, этот подход потребует дополнительных усилий.

Правильный подход: использование QAbstractTextDocumentLayout::PaintContext

Для отрисовки выделения без изменения QTextCharFormat можно использовать QAbstractTextDocumentLayout::PaintContext. Этот метод позволяет отрисовать выделение текста, не изменяя его форматирование.

Как это работает

QAbstractTextDocumentLayout::PaintContext содержит информацию о том, как должен быть отрисован документ. В частности, он позволяет задать выделенные области (selections).

Пример кода

Вот как можно использовать PaintContext для отрисовки выделения:

#include <QTextDocument>
#include <QAbstractTextDocumentLayout>
#include <QPainter>
#include <QTextCursor>

void drawTextDocumentWithSelection(QTextDocument* document, QPainter* painter, const QTextCursor& cursor) {
    // Создаем контекст отрисовки
    QAbstractTextDocumentLayout::PaintContext context;

    // Если есть выделение, добавляем его в контекст
    if (cursor.hasSelection()) {
        QTextCharFormat selectionFormat;
        selectionFormat.setBackground(Qt::blue); // Цвет подсветки
        selectionFormat.setForeground(Qt::white); // Цвет текста

        QAbstractTextDocumentLayout::Selection selection;
        selection.cursor = cursor;
        selection.format = selectionFormat;

        context.selections.append(selection);
    }

    // Отрисовываем документ с учетом контекста
    document->documentLayout()->draw(painter, context);
}

Как использовать

  1. Создайте QTextDocument и установите текст:

    QTextDocument document;
    document.setPlainText("Hello, this is a sample text.");
  2. Создайте QTextCursor и выделите текст:

    QTextCursor cursor(&document);
    cursor.movePosition(QTextCursor::Start);
    cursor.movePosition(QTextCursor::End, QTextCursor::KeepAnchor);
  3. Отрисуйте документ с выделением:

    QPainter painter(this);
    drawTextDocumentWithSelection(&document, &painter, cursor);

Преимущества этого подхода

  1. Не изменяет форматирование текста: Выделение отрисовывается не затрагивая QTextCharFormat, что вам очень пригодится если вы захотите работать с очередью команд QTextDocument.

  2. Гибкость: Вы можете легко изменять цвет, прозрачность и другие параметры выделения.

  3. Производительность: Этот метод не требует изменения структуры документа, что делает его быстрым.

Заключение

Использование QAbstractTextDocumentLayout::PaintContext для отрисовки выделения текста в QTextDocument — это правильный и гибкий подход. Он позволяет отрисовать выделение без изменения форматирования текста и подходит для сложных сценариев, таких как подсветка синтаксиса или временное выделение.

Если вы работаете с QTextDocument и вам нужно отрисовать выделение, попробуйте этот метод. Он сэкономит вам время и упростит код.

P.S.
Статья целиком оформлена в DeepSeek. Мы вместе с ним довольно долго копались в QTextDocument, так что он точно передал мои мысли и идею, ведь в большинстве статей и форумных веток действительно предлагается вручную корежить данные самого документа для отрисовки выделения, но это в корне неверный и люто геморройный джуниорский подход. Я потратил пару дней на доскональное изучение исходников Qt, объяснил все DeepSeek, и попросил оформить это в хорошую и понятную статью. Так что не думайте, что он все сделал сам :) он только оформил:)

Комментарии (1)


  1. wingooey
    13.02.2025 09:29

    Т.к речь идёт об интерфейсе и о правильной отрисовке, было бы интересно посмотреть на скриншоты неправильной, и правильной отрисовки.