Введение
Работа с текстом в 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);
}
Как использовать
-
Создайте QTextDocument и установите текст:
QTextDocument document; document.setPlainText("Hello, this is a sample text.");
-
Создайте QTextCursor и выделите текст:
QTextCursor cursor(&document); cursor.movePosition(QTextCursor::Start); cursor.movePosition(QTextCursor::End, QTextCursor::KeepAnchor);
-
Отрисуйте документ с выделением:
QPainter painter(this); drawTextDocumentWithSelection(&document, &painter, cursor);
Преимущества этого подхода
Не изменяет форматирование текста: Выделение отрисовывается не затрагивая QTextCharFormat, что вам очень пригодится если вы захотите работать с очередью команд QTextDocument.
Гибкость: Вы можете легко изменять цвет, прозрачность и другие параметры выделения.
Производительность: Этот метод не требует изменения структуры документа, что делает его быстрым.
Заключение
Использование QAbstractTextDocumentLayout::PaintContext для отрисовки выделения текста в QTextDocument — это правильный и гибкий подход. Он позволяет отрисовать выделение без изменения форматирования текста и подходит для сложных сценариев, таких как подсветка синтаксиса или временное выделение.
Если вы работаете с QTextDocument и вам нужно отрисовать выделение, попробуйте этот метод. Он сэкономит вам время и упростит код.
P.S.
Статья целиком оформлена в DeepSeek. Мы вместе с ним довольно долго копались в QTextDocument, так что он точно передал мои мысли и идею, ведь в большинстве статей и форумных веток действительно предлагается вручную корежить данные самого документа для отрисовки выделения, но это в корне неверный и люто геморройный джуниорский подход. Я потратил пару дней на доскональное изучение исходников Qt, объяснил все DeepSeek, и попросил оформить это в хорошую и понятную статью. Так что не думайте, что он все сделал сам :) он только оформил:)
wingooey
Т.к речь идёт об интерфейсе и о правильной отрисовке, было бы интересно посмотреть на скриншоты неправильной, и правильной отрисовки.