Сталкивались ли вы с ситуацией, когда пользователь “вводит как попало”, а приложение затем рассыпается на ошибках, странных значениях и бесконечных обработчиках? Каждый Qt-разработчик знает это чувство: интерфейс уже готов, а ввод данных превращается в минное поле.
Эта глава раскроет, как превратить ввод в управляемый процесс: аккуратный, предсказуемый и дружелюбный для пользователя. Здесь обнаружите неочевидный инсайт: многие задачи ввода (буфер обмена, drag & drop, выделение, отмена/повтор) уже решены Qt — нужно лишь правильно “включить” их, а не писать велосипед. Результат — меньше кода, меньше багов, быстрее разработка.
В фокусе — связка QLineEdit + сигналы textChanged/textEdited, режим Password, “умные” ограничения через QValidator, а также работа с документом через QTextEdit/QTextDocument (включая экспорт в ODF/HTML и печать в PDF через QPrinter). Плюс — практичный разбор QSyntaxHighlighter: почему профессиональные разработчики используют подсветку, даже в утилитах.
Не откладывайте: одна неверная стратегия ввода обычно всплывает уже на первом релизе — и ремонт обходится дороже, чем правильный старт.
В этой главе вы найдёте готовые к использованию примеры кода.
Самопроверка по главе
В чём ключевое различие между сигналами textChanged() и textEdited() в QLineEdit?Ответ
Правильный ответ: textChanged() отправляется при любом изменении текста (включая программное через setText()), а textEdited() — только при изменениях, сделанных пользователем вручную.
Почему для редактирования обычного текста рекомендуется использовать QPlainTextEdit вместо QTextEdit?Ответ
Правильный ответ: QPlainTextEdit не поддерживает RTF-форматирование, что делает его более легковесным, простым и эффективным для работы с простым текстом.
Какую роль выполняет объект QTextDocument в виджетах редактирования текста?Ответ
Правильный ответ: QTextDocument хранит содержимое документа и предоставляет методы для работы с ним (undo/redo, поиск, форматирование); многие методы QTextEdit являются делегирующими к QTextDocument.
Почему в примере с подсветкой синтаксиса не сохраняется указатель на объект SyntaxHighlighter после его создания?Ответ
Правильный ответ: Объект SyntaxHighlighter автоматически устанавливает QTextDocument как родителя, который будет управлять его памятью и автоматически удалит при своём уничтожении.
Зачем в примере с расцветкой синтаксиса используются состояния InsideCStyleComment и InsideCString?Ответ
Правильный ответ: Метод highlightBlock() обрабатывает только одну строку за раз, поэтому состояния необходимы для отслеживания многострочных конструкций (комментариев /**/ и строк), которые могут начинаться в одной строке и заканчиваться в другой.
Какие три значения может возвращать метод validate() и когда каждое из них используется?Ответ
Правильный ответ: Invalid — строка не может быть принята; Intermediate — строка не окончательна (например, “1” при диапазоне 50-100); Acceptable — строка корректна и может быть принята.
Зачем нужно состояние Intermediate в валидаторе, если есть Invalid и Acceptable?Ответ
Правильный ответ: Intermediate позволяет пользователю вводить промежуточные значения в процессе набора (например, при вводе “100” сначала будет введена “1”), не блокируя ввод преждевременно.
Как создать PDF-файл из содержимого QTextEdit без использования QTextDocumentWriter?Ответ
Правильный ответ: Нужно создать объект QPrinter с режимом высокого разрешения, установить формат PdfFormat, задать имя файла и вызвать метод document()->print(&printer).
В каких ситуациях лучше использовать setReadOnly(true) вместо валидатора?Ответ
Правильный ответ: setReadOnly() подходит, когда нужно полностью запретить редактирование и оставить только просмотр; валидатор же используется для контроля формата вводимых данных при разрешённом редактировании.
Почему метод append() в QTextEdit работает быстрее и требует меньше памяти, чем insertPlainText()?Ответ
Правильный ответ: Добавленный через append() текст не вносится в список операций для undo(), что исключает необходимость хранения истории изменений для этой операции.
Какие готовые классы валидаторов предоставляет Qt и для чего они используются?Ответ
Правильный ответ: QIntValidator и QDoubleValidator для проверки ввода целых чисел и чисел с плавающей точкой соответственно; QRegularExpressionValidator для валидации с помощью регулярных выражений.
Практические задания
Простой уровень
Форма регистрации с валидацией
Создайте простую форму регистрации с тремя полями: имя пользователя (только буквы), email и пароль (скрытый ввод). Добавьте метку, которая показывает, сколько символов введено в поле имени. Реализуйте собственный валидатор для поля имени, запрещающий ввод цифр и специальных символов.
Подсказки: Используйте QLineEdit для полей ввода. Для пароля примените setEchoMode(QLineEdit::Password). Создайте класс валидатора, унаследованный от QValidator, и проверяйте символы с помощью QString::contains() и регулярных выражений. Подключите сигнал textChanged() к слоту для обновления счётчика символов.
Средний уровень
Простой текстовый редактор с форматированием
Создайте текстовый редактор на основе QTextEdit с панелью инструментов, содержащей кнопки для: сохранения в HTML и PDF, очистки текста, отмены/повтора действий, увеличения/уменьшения шрифта. Добавьте счётчик слов, который обновляется при изменении текста. Реализуйте возможность открытия и отображения простых HTML-файлов.
Подсказки: Используйте QVBoxLayout для компоновки. Создайте QHBoxLayout для кнопок. Для сохранения в PDF используйте QPrinter с setOutputFormat(QPrinter::PdfFormat). Подключите сигналы undoAvailable/redoAvailable для управления активностью кнопок. Для подсчёта слов используйте toPlainText().split(QRegularExpression(“\\s+”), Qt::SkipEmptyParts).count().
Сложный уровень
Редактор с подсветкой синтаксиса JSON
Создайте редактор для JSON-файлов с собственной подсветкой синтаксиса. Реализуйте QSyntaxHighlighter, который раскрашивает: ключи (синим), строковые значения (зелёным), числа (оранжевым), булевы значения и null (фиолетовым), фигурные и квадратные скобки (жирным). Добавьте валидацию JSON в реальном времени — при вводе некорректного JSON показывайте индикатор ошибки и подсвечивайте проблемную строку красным фоном.
Подсказки: Унаследуйте QSyntaxHighlighter и реализуйте highlightBlock(). Используйте регулярные выражения для поиска паттернов: ключей (“.*”:), строк (“.*”), чисел (\b\d+\.?\d*\b). Для валидации используйте QJsonDocument::fromJson() и проверяйте наличие ошибок парсинга. Применяйте setFormat() с QTextCharFormat для подсветки фона проблемных строк. Используйте previousBlockState() для отслеживания многострочных строк.
💬 Присоединяйтесь к обсуждению!
Разобрались с элементами ввода и валидацией? Удалось реализовать собственную подсветку синтаксиса?
Поделитесь своими находками по работе с QTextEdit, расскажите о сложностях с валидаторами или задайте вопросы о подсветке синтаксиса!
Возможно, вы нашли более элегантное решение для алгоритма расцветки или интересный способ применения QSyntaxHighlighter?