Фокус клавиатуры в виджетах
Виджеты Qt обрабатывают фокус клавиатуры привычным для GUI способом.
Основная проблема заключается в том, что нажатия клавиш пользователя могут быть направлены на любое из нескольких окон на экране и на любой из нескольких виджетов внутри целевого окна. Пользователь ожидает, что нажатие клавиши попадет в нужное место, и программное обеспечение должно попытаться удовлетворить это ожидание. Система должна определить, к какому приложению направлено нажатие клавиши, к какому окну в этом приложении и к какому виджету в этом окне.
Движение фокуса
Принятые правила для направления фокуса клавиатуры на конкретный виджет таковы:
- Пользователь нажимает клавишу Tab (или Shift+Tab).
- Пользователь щелкает по виджету.
- Пользователь нажимает сочетание клавиш.
- Пользователь использует колесо мыши.
- Пользователь перемещает фокус в окно, и приложение должно определить, какой виджет внутри окна должен получить фокус.
Каждый из этих механизмов движения отличается, и различные типы виджетов получают фокус только при некоторых из них. Мы рассмотрим каждый из них по очереди.
Клавиша Tab или Shift+Tab
Нажатие клавиши Tab является наиболее распространённым способом перемещения фокуса с помощью клавиатуры. (Иногда в приложениях для ввода данных клавиша Enter выполняет ту же функцию, что и Tab; это легко достигается в Qt путём реализации фильтра событий фильтра событий.)
Нажатие клавиши Tab во всех используемых сегодня оконных системах перемещает фокус клавиатуры к следующему виджету в циклическом списке в рамках каждого окна. Tab перемещает фокус по циклическому списку в одном направлении, а Shift+Tab — в другом. Порядок, в котором нажатия клавиши Tab перемещают фокус с виджета на виджет, называется порядком табуляции.
Вы можете настроить порядок табуляции, используя QWidget::setTabOrder(). (Если этого не сделать, Tab обычно перемещает фокус в порядке создания виджетов.) Qt Designer предоставляет средства для визуального изменения порядка табуляции.
Поскольку нажатие клавиши Tab очень распространено, большинство виджетов, которые могут получить фокус, должны поддерживать фокус табуляции. Основное исключение — виджеты, которые редко используются, и где существует какое-то сочетание клавиш или обработчик ошибок, перемещающий фокус.
Например, в диалоговом окне ввода данных может быть поле, необходимое только в одном случае из ста. В таком диалоговом окне клавиша Tab может пропустить это поле, и диалоговое окно может использовать один из этих механизмов:
- Если программа может определить, нужно ли поле, она может переместить фокус туда, когда пользователь закончит ввод и нажмёт OK или когда пользователь нажмёт Enter после заполнения других полей. Альтернативно, включите поле в порядок табуляции, но отключите его. Включите его, если это станет уместно с учётом того, что пользователь ввёл в другие поля.
- Метка поля может включать сочетание клавиш, которое перемещает фокус в это поле.
Ещё одно исключение из поддержки Tab — это виджеты ввода текста, которые должны поддерживать вставку знаков табуляции; практически все текстовые редакторы относятся к этому классу. Qt рассматривает Ctrl+Tab как Tab, а Ctrl+Shift+Tab как Shift+Tab, и такие виджеты могут переопределять QWidget::event() и обрабатывать Tab перед вызовом QWidget::event() для получения обычной обработки всех остальных клавиш. Однако, поскольку некоторые системы используют Ctrl+Tab для других целей, а многие пользователи и не знают о Ctrl+Tab, это не является полным решением.
Нажатие пользователя на виджет
Это, пожалуй, ещё более распространено, чем нажатие клавиши Tab на компьютерах с мышью или другим устройством указания.
Щелканье для перемещения фокуса немного мощнее, чем Tab. В то время как оно перемещает фокус к виджету, для виджетов редактора оно также перемещает курсор текста (внутренний фокус виджета) в точку, где нажата мышь.
Поскольку это так распространено и люди привыкли к этому, целесообразно поддерживать его для большинства виджетов. Однако есть и важная причина для избегания этого: возможно, вы не хотите убирать фокус с виджета, где он был.
Например, в текстовом редакторе, когда пользователь нажимает на кнопку инструмента 'B' (полужирный шрифт), что должно произойти с фокусом клавиатуры? Должен ли он остаться там, где был, почти наверняка в виджете редактирования, или он должен переместиться на кнопку 'B'?
Мы рекомендуем поддерживать щелчок для перемещения фокуса для виджетов, поддерживающих ввод текста, и избегать его для большинства виджетов, где щелчок мышью имеет другое действие. (Для кнопок мы также рекомендуем добавить сочетание клавиш: QAbstractButton и его подклассы делают это очень легко.)
В Qt только функция QWidget::setFocusPolicy() влияет на щелчок для перемещения фокуса.
Нажатие пользователя на сочетание клавиш
Необычным не является перемещение фокуса с помощью сочетаний клавиш. Это может происходить неявно при открытии модальных диалоговых окон, но также явно с помощью акселеров фокуса, таких как те, которые предоставляются QLabel::setBuddy(), QGroupBox и QTabBar.
Мы рекомендуем поддерживать фокус сочетаний клавиш для всех виджетов, к которым пользователь может захотеть перейти. Например, диалоговое окно вкладок может иметь сочетания клавиш для каждой его страницы, поэтому пользователь может нажать, например, Alt+P, чтобы перейти на страницу Pечать. Легко переусердствовать: существует всего несколько клавиш, и также важно предоставить сочетания клавиш для команд. Alt+P также используется для Вставки, Воспроизведения, Печати и Печати сюда в списке Стандартных сочетаний клавиш, например.
Поворот колеса мыши пользователем
В Microsoft Windows использование колеса мыши всегда обрабатывается виджетом, имеющим фокус клавиатуры. В macOS и X11 — виджетом, получающим другие события мыши.
Способ, которым Qt обрабатывает это различие между платформами, заключается в том, что виджеты перемещают фокус клавиатуры при использовании колеса. С правильной политикой фокусировки на каждом виджете приложения могут работать адекватно на Windows, macOS и X11.
Перемещение фокуса в это окно пользователем
В этой ситуации приложение должно определить, какой виджет внутри окна должен получить фокус.
Это может быть просто: если фокус был в этом окне раньше, то последний виджет, имевший фокус, должен его снова получить. Qt делает это автоматически.
Если фокус никогда не был в этом окне и вы знаете, с какого виджета фокус должен начаться, вызовите QWidget::setFocus() на виджете, который должен получить фокус, перед вызовом QWidget::show() для него. Если этого не сделать, Qt выберет подходящий виджет.
© The Qt Company Ltd
Licensed under the GNU Free Documentation License, Version 1.3.
https://doc.qt.io/qt-5.14/focus.html