Эта глава раскроет скрытую механику пользовательского ввода в QML. Здесь вы обнаружите, как мышь, клавиатура и мультитач подчиняются одной логике, узнаете секрет правильного выбора между сигналами и свойствами и раскроем, как избежать типичных ловушек фокуса и событий. Результат — более предсказуемое поведение интерфейса и заметно меньше багов уже на этапе прототипа.
Будут разобраны MouseArea, собственные сигналы, управление фокусом через KeyNavigation, «сырой» ввод через Keys и работа с MultiPointTouchArea. На практике это позволяет сократить код обработчиков в разы и добиться реакции интерфейса быстрее, чем при классическом подходе.
Пропустить эту главу — значит продолжать чинить симптомы вместо причины.
В этой главе вы найдёте готовые к использованию примеры кода.
Самопроверка по главе
Почему элементу TextInput необходимо явно задавать ширину через свойство width, даже если текст пустой?Ответ
Правильный ответ: Если TextInput не содержит текста, его ширина становится равной 0, что делает невозможным клик по элементу для получения фокуса. Явное задание ширины гарантирует возможность взаимодействия даже с пустым полем.
В чём принципиальная разница между использованием сигнала clicked и свойства clicked для кнопки?Ответ
Правильный ответ: Сигнал передаёт событие в одном направлении и получатель не может изменить состояние отправителя; свойство же позволяет двустороннюю связь и изменение значений. Обработчик для свойства называется onClickedChanged, а для сигнала — onClicked.
Зачем в MouseArea используется параметр acceptedButtons?Ответ
Правильный ответ: Он ограничивает срабатывание обработчиков только определёнными кнопками мыши (например, только левой и правой), предотвращая реакцию на нежелательные события от других кнопок.
Что произойдёт, если не установить hoverEnabled: true для MouseArea при использовании onEntered/onExited?Ответ
Правильный ответ: Обработчики onEntered и onExited не будут срабатывать, так как по умолчанию MouseArea не отслеживает события наведения курсора, а реагирует только на клики.
Почему в примере с кнопкой размеры BorderImage увеличены на 15 пикселов относительно размеров текста?Ответ
Правильный ответ: Это создаёт внутренние отступы (padding) вокруг текста, обеспечивая визуально привлекательный внешний вид кнопки, где текст не прилипает к краям.
Когда целесообразнее использовать сигналы вместо свойств для взаимодействия между элементами?Ответ
Правильный ответ: Сигналы предпочтительны для взаимодействия между автономными, независимыми элементами, где не требуется обратная связь. Свойства лучше подходят для связи элементов внутри одного родительского контейнера.
Как работает механизм автоматической генерации обработчиков для пользовательских сигналов?Ответ
Правильный ответ: При объявлении сигнала через ключевое слово signal автоматически создаётся обработчик с префиксом “on” и именем сигнала с заглавной буквы (например, для signal mousePositionChanged создаётся onMousePositionChanged).
Что произойдёт, если в MultiPointTouchArea задать больше элементов TouchPoint, чем указано в maximumTouchPoints?Ответ
Правильный ответ: Лишние TouchPoint не будут активироваться, так как maximumTouchPoints ограничивает количество одновременно обрабатываемых касаний. Обработаются только первые N касаний согласно заданному лимиту.
Зачем использовать прикрепляемое свойство KeyNavigation.tab вместо простого изменения фокуса в обработчике Keys.onPressed?Ответ
Правильный ответ: KeyNavigation.tab предоставляет декларативный способ описания навигации, делая код более читаемым и упрощая управление фокусом без необходимости писать императивную логику обработки событий.
В каких случаях нужно использовать Keys.forwardTo и какие элементы можно туда передавать?Ответ
Правильный ответ: Keys.forwardTo используется для пересылки событий клавиатуры другим элементам для дальнейшей обработки. Можно передавать как отдельные элементы, так и списки объектов.
Почему элемент TouchPoint сравнивают с MouseArea?Ответ
Правильный ответ: TouchPoint функционально аналогичен MouseArea, но для сенсорного ввода — каждый TouchPoint отслеживает отдельную точку касания, подобно тому как MouseArea отслеживает одну мышь.
Что случится, если TextInput или TextEdit не получит фокус при попытке пользователя ввести текст?Ответ
Правильный ответ: Ввод текста не будет работать, так как события клавиатуры обрабатываются только элементом, имеющим активный фокус. Пользователю придётся сначала кликнуть на элемент мышью для получения фокуса.
Зачем в примере с мультитач используется Repeater для создания визуализации касаний?Ответ
Правильный ответ: Repeater автоматически создаёт визуальные элементы (прямоугольники) для каждого TouchPoint из массива, избавляя от необходимости дублировать код для каждого касания и обеспечивая синхронизацию с данными modelData.
Практические задания
Простой уровень
Интерактивная визитка с эффектами наведения
Создайте прямоугольную визитную карточку, которая содержит ваше имя и профессию. При наведении курсора мыши карточка должна менять цвет фона, а при клике левой кнопкой — увеличивать размер шрифта текста. При клике правой кнопкой размер шрифта должен уменьшаться.
Подсказки: Используйте Rectangle с вложенным Text. В MouseArea установите hoverEnabled: true для отслеживания наведения. Используйте свойство containsMouse для изменения цвета. В обработчике onPressed проверяйте mouse.button и изменяйте font.pixelSize текста через parent или id.
Средний уровень
Калькулятор простых операций с клавиатурным вводом
Создайте простой калькулятор с двумя полями TextInput для ввода чисел и отображением результата. Пользователь должен иметь возможность переключаться между полями клавишей Tab. Добавьте обработку клавиш ‘+’, ‘-‘, ‘*’, ‘/’ для выполнения соответствующих операций и отображения результата в элементе Text. При нажатии Enter результат должен копироваться в первое поле.
Подсказки: Используйте два TextInput с настроенным KeyNavigation.tab. Для обработки арифметических клавиш используйте Keys.onPressed и проверяйте event.key (Qt.Key_Plus и т.д.). Для преобразования текста в числа используйте parseFloat() или Number(). Проверяйте корректность ввода. Не забудьте установить focus: true первому полю.
Сложный уровень
Мультитач-рисовалка с историей действий
Создайте приложение для рисования, поддерживающее до 5 одновременных касаний. Каждое касание должно оставлять след в виде цветной линии (разные цвета для разных пальцев). Реализуйте историю последних 10 касаний с отображением координат startX/startY, текущих x/y и силы нажатия (pressure). Добавьте кнопку очистки холста с пользовательским сигналом clearRequested и возможность отмены последнего действия по нажатию клавиши ‘Z’.
Подсказки: Используйте MultiPointTouchArea с массивом TouchPoint. Для рисования используйте Canvas с методом requestPaint(). В обработчиках onPressureChanged или onPositionChanged сохраняйте координаты в JavaScript-массив. Для истории создайте ListModel с элементами делегата. Создайте собственную кнопку с signal clearRequested. Для обработки клавиши используйте Keys.onPressed с проверкой event.key == Qt.Key_Z.
💬 Присоединяйтесь к обсуждению!
Разобрались с обработкой пользовательского ввода в QML? Возникли вопросы о выборе между сигналами и свойствами?
Поделитесь своим опытом реализации интерактивных элементов, обсудите нюансы работы с фокусом или расскажите о решении проблем с мультитач! Ваш опыт может помочь другим читателям освоить эти концепции быстрее.