Spec-Zone .ru
спецификации, руководства, описания, API

Подсистема Фокуса AWT

До Java 2 Standard Edition, JDK 1.4, подсистема фокуса AWT была несоответствующей. Это пострадало от главного проекта и проблем API, так же как более чем ста открытых ошибок. Многие из этих ошибок были вызваны несогласованностями платформы, или несовместимостями между собственной системой фокуса для тяжеловесов и системой фокуса Java для легких весов.

Единственной худшей проблемой с реализацией фокуса AWT была неспособность запросить для в настоящий момент фокусируемого Компонента. Мало того, что не было никакого API для такого запроса, но также и, из-за недостаточной архитектуры, такая информация даже не сохранялась кодом.

Почти как плохо была неспособность легких дочерних элементов Окна (не Фрейм или Диалоговое окно), чтобы получить ввод клавиатуры. Эта проблема существовала потому что Windows, никогда получаемый WINDOW_ACTIVATED события и таким образом никогда не могли активироваться, и только активные окна могли содержать фокусируемые Компоненты.

Кроме того, много разработчиков отметили, что API для FocusEvent и WindowEvent были недостаточны, потому что они не обеспечивали путь к определению "противоположного" Компонента, включенного в изменение активации или фокус. Например, когда Компонент, полученный событие FOCUS_LOST, у этого не было никакого способа знать, какой Компонент получал фокус. Так как Microsoft Windows обеспечивает эту функциональность бесплатно, разработчики, переходящие от C/C++ Microsoft Windows или Visual Basic к Java, были расстроены пропуском.

Чтобы адресовать эти и другие недостатки, мы разработали новую модель фокуса для AWT в JDK 1.4. Основные конструктивные изменения были конструкцией нового централизованного класса KeyboardFocusManager, и легкой архитектурой фокуса. Количество связанного с фокусом, зависимого от платформы кода было минимизировано и заменено полностью сменными и расширяемыми общедоступными API в AWT. В то время как мы попытались остаться обратно совместимыми с существующей реализацией, мы были вынуждены произвести незначительные несовместимые изменения, чтобы сделать изящный и осуществимый вывод. Мы ожидаем, что эти несовместимости окажут только тривиальное влияние на существующие приложения.

Этот документ является формальной спецификацией оба из новых API и существующих API, которые остаются релевантными в новой модели. Объединенный с javadoc для связанных с фокусом классов и методов, этот документ должен позволить разработчикам создать существенный AWT и приложения Swing с поведением фокуса, которое настраивается все же непротиворечивое через платформы. У этого документа есть следующие разделы:

Краткий обзор KeyboardFocusManager

Модель фокуса централизуется вокруг единого класса, KeyboardFocusManager, который обеспечивает ряд API для клиентского кода, чтобы запросить о текущем состоянии фокуса, начатых изменениях фокуса, и диспетчеризации события фокуса значения по умолчанию замены с пользовательским диспетчером. Клиенты могут запросить о состоянии фокуса непосредственно, или могут зарегистрировать PropertyChangeListener, который получит PropertyChangeEvents, когда изменение к состоянию фокуса произойдет.

KeyboardFocusManager представляет следующие основные понятия и их терминологию:

  1. "Владелец фокуса" - Компонент, который обычно получает ввод клавиатуры.
  2. "Постоянный владелец фокуса" - последний Компонент, который получит фокус постоянно. "Владелец фокуса" и "постоянный владелец фокуса" эквивалентны, если временное изменение фокуса не в настоящий момент в действительности. В такой ситуации "постоянный владелец фокуса" снова будет "владельцем фокуса", когда временное изменение фокуса закончится.
  3. "Фокусируемое Окно" - Окно, которое содержит "владельца фокуса".
  4. "Активное окно" - Фрейм или Диалоговое окно, которое является или "фокусируемым Окном", или первым Фреймом или Диалоговым окном, которое является владельцем "фокусируемого Окна".
  5. "Обход фокуса" - возможность пользователя изменить "владельца фокуса", не перемещая курсор. Как правило, это делается, используя клавиатуру (например, при использовании клавиши TAB), или эквивалентное устройство в доступной среде. Клиентский код может также инициировать обход программно. Нормальный обход фокуса может быть или "вперед" к "следующему" Компоненту, или "назад" к "предыдущему" Компоненту.
  6. "Цикл обхода фокуса" - часть Иерархии компонентов, так, что нормальный обход фокуса "вперед" (или "назад") пересечет через все Компоненты в цикле фокуса, но никакие другие Компоненты. Этот цикл обеспечивает отображение от произвольного Компонента в цикле к его "следующему" (прямой обход) и "предыдущий" (обратный обход) Компоненты.
  7. "Проходимый Компонент" - Компонент, который находится в цикле обхода фокуса.
  8. "Непроходимый Компонент" - Компонент, который не находится в цикле обхода фокуса. Отметьте, что непроходимый Компонент может однако фокусироваться другим способом (например, прямым запросом фокуса).
  9. "Цикл фокуса базируется" - Контейнер, который является корнем Иерархии компонентов для определенного "цикла обхода фокуса". Когда "владельцем фокуса" является Компонент в определенном цикле, нормальный прямой и обратный обход фокуса не может переместить "владельца фокуса" выше корня цикла фокуса в Иерархии компонентов. Вместо этого две дополнительных операции обхода, "цикл" и "вниз цикл", определяются, чтобы позволить клавиатуру и программируемую навигацию вверх и вниз по иерархии цикла обхода фокуса.
  10. "Провайдер политики обхода фокуса" - Контейнер, у которого есть свойство "FocusTraversalPolicyProvider" как истина. Этот Контейнер будет использоваться, чтобы получить политику обхода фокуса. Этот контейнер не определяет новый цикл фокуса, но только изменяет порядок, согласно которому его дочерние элементы пересекаются "вперед" и "назад". Провайдер политики обхода фокуса может быть установлен, используя setFocusTraversalPolicyProvider на Контейнере.

Каждое Окно и JInternalFrame являются, по умолчанию, "корнем цикла фокуса". Если это - единственный корень цикла фокуса, то все его focusable потомки должны быть в его цикле фокуса, и его политика обхода фокуса должна осуществить это, они, удостоверяясь, что все будут достигнуты во время прямого нормального (или назад) обход. Если, с другой стороны, Окно или JInternalFrame имеет потомков, которые являются также корнями цикла фокуса, то каждый такой потомок является элементом двух циклов фокуса: тот, что это - корень, и то его самого близкого корневого циклом фокусом предка. Чтобы пересечь focusable компоненты, принадлежащие циклу фокуса такого "порожденного" корня цикла фокуса, первые пересечения (вперед или назад), чтобы достигнуть потомка, и затем использует "вниз цикл" работа, чтобы достигнуть, поочередно, ее потомков.

Вот пример:
Три группы как описано ниже: BDE ABCF и DGH.

Примите следующее:

В этом примере есть в общей сложности три корня цикла фокуса:
  1. A является корнем, и A, B, C, и F являются элементами цикла А.
  2. B является корнем, и B, D, и E являются элементами цикла Б.
  3. D является корнем, и D, Г, и H являются элементами цикла Д.
Windows являются единственные Контейнеры, которые, по умолчанию, являются корнями цикла фокуса. KeyboardFocusManager абстрактный класс. AWT обеспечивает реализацию по умолчанию в DefaultKeyboardFocusManager класс.

KeyboardFocusManager и Контексты Браузера

Некоторые апплеты раздела браузеров в различных кодовых базах в отдельные контексты, и устанавливают стены между этими контекстами. Каждый поток и каждый Компонент связываются с определенным контекстом и не могут вмешаться в потоки или Компоненты доступа в других контекстах. В таком сценарии будет один KeyboardFocusManager на контекст. Другие браузеры помещают все апплеты в тот же самый контекст, подразумевая, что будет только единственный, глобальный KeyboardFocusManager для всех апплетов. Это поведение является зависящим от реализации. Консультируйтесь с документацией своего браузера для получения дополнительной информации. Независимо от того, сколькими контексты там могут быть, однако, никогда не может быть больше чем одного владельца фокуса, фокусируемого Окна, или активного окна, на ClassLoder.

KeyEventDispatcher и KeyEventPostProcessor

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

KeyEventDispatcher является легким интерфейсом, который позволяет клиентскому коду предварительно слушать весь KeyEvents в определенном контексте. Экземпляры классов, которые реализуют интерфейс и регистрируются в текущем KeyboardFocusManager, получат KeyEvents прежде, чем они будут диспетчеризированы владельцу фокуса, разрешая KeyEventDispatcher перенастроить событие, использовать это, диспетчеризировать это непосредственно, или произвести другие изменения.

Для непротиворечивости самим KeyboardFocusManager является KeyEventDispatcher. По умолчанию текущий KeyboardFocusManager будет приемником для всего KeyEvents, не диспетчеризированного зарегистрированным KeyEventDispatchers. Текущий KeyboardFocusManager не может быть полностью вычеркнут из списка как KeyEventDispatcher. Однако, если KeyEventDispatcher сообщит, что диспетчеризировал KeyEvent, независимо от того, сделал ли он фактически так, то KeyboardFocusManager не предпримет дальнейших мер относительно KeyEvent. (В то время как для клиентского кода возможно зарегистрировать текущий KeyboardFocusManager как KeyEventDispatcher один или более раз, нет никакой очевидной причины, почему это было бы необходимо, и поэтому это не рекомендуется.)

Клиентский код может также постслушать KeyEvents в определенном контексте, используя интерфейс KeyEventPostProcessor. KeyEventPostProcessors, зарегистрированный в текущем KeyboardFocusManager, получит KeyEvents после того, как KeyEvents были диспетчеризированы и обработаны владельцем фокуса. KeyEventPostProcessors также получит KeyEvents, который был бы иначе отброшен, потому что никакому Компоненту в приложении в настоящий момент не принадлежит фокус. Это позволит приложениям реализовать опции, которые требуют глобального KeyEvent пост - обработка, такая как ярлыки меню.

Как KeyEventDispatcher, KeyboardFocusManager также реализует KeyEventPostProcessor, и подобные ограничения применяются к его использованию в той емкости.

FocusEvent и WindowEvent

AWT определяет следующие шесть типов события, центральных к модели фокуса в два отличающийся java.awt.event классы:

  1. WindowEvent.WINDOW_ACTIVATED: Это событие диспетчеризируется Фрейму или Диалоговому окну (но никогда Окно, которое не является Фреймом или Диалоговым окном), когда это становится активным окном.
  2. WindowEvent.WINDOW_GAINED_FOCUS: Это событие диспетчеризируется Окну, когда это становится фокусируемым Окном. Только Windows focusable может получить это событие.
  3. FocusEvent.FOCUS_GAINED: Это событие диспетчеризируется Компоненту, когда это становится владельцем фокуса. Только Компоненты focusable могут получить это событие.
  4. FocusEvent.FOCUS_LOST: Это событие диспетчеризируется Компоненту, когда это больше не владелец фокуса.
  5. WindowEvent.WINDOW_LOST_FOCUS: Это событие диспетчеризируется Окну, когда это больше не фокусируемое Окно.
  6. WindowEvent.WINDOW_DEACTIVATED: Это событие диспетчеризируется Фрейму или Диалоговому окну (но никогда Окно, которое не является Фреймом или Диалоговым окном), когда это больше не активное окно.

Поставка события

Если фокус не будет в приложении java, и пользователь щелкает по focusable дочернему элементу Компоненте неактивного Фрейма b, то следующие события будут диспетчеризированы и обработаны в порядке:

  1. b получит a WINDOW_ACTIVATED событие.
  2. Затем, b получит a WINDOW_GAINED_FOCUS событие.
  3. Наконец, желание получают a FOCUS_GAINED событие.
Если пользователь позже щелкнет по focusable дочернему Компоненту c другого Фрейма d, то следующие события будут диспетчеризированы и обработаны в порядке:
  1. желание получает a FOCUS_LOST событие.
  2. b получит a WINDOW_LOST_FOCUS событие.
  3. b получит a WINDOW_DEACTIVATED событие.
  4. d получит a WINDOW_ACTIVATED событие.
  5. d получит a WINDOW_GAINED_FOCUS событие.
  6. c получит a FOCUS_GAINED событие.
Отметьте, что каждое событие будет полностью обработано прежде, чем следующее событие диспетчеризируется. Это ограничение будет осуществлено, даже если Компоненты будут в различных контекстах и будут обработаны на различных потоках диспетчеризации события.

Кроме того, каждый тип события будет диспетчеризирован в 1 к 1 корреспонденции ее противоположному типу события. Например, если Компонент получает a FOCUS_GAINED событие, ни в коем случае не может это никогда принимать другого FOCUS_GAINED событие без вмешательства FOCUS_LOST событие.

Наконец, важно отметить, что эти события поставляются для информационных целей только. Невозможно, например, предотвратить поставку ожидания FOCUS_GAINED событие, запрашивая фокус назад к Компонентной потере фокусируется, обрабатывая предыдущее FOCUS_LOST событие. В то время как клиентский код может обратиться с такой просьбой, ожиданием FOCUS_GAINED будет все еще поставлен, сопровождаться позже событиями, возвращающими фокус исходному владельцу фокуса.

Если абсолютно необходимо подавить FOCUS_GAINED событие, клиентский код может установить a VetoableChangeListener который отклоняет изменение фокуса. См. Фокус и VetoableChangeListener.

Противоположные Компоненты и Windows

Каждое событие включает информацию о "противоположном" Компоненте или Окне, включенном в изменение активации или фокус. Например, для a FOCUS_GAINED событие, противоположным Компонентом является Компонент, который потерял фокус. Если изменение фокуса или активации происходит с собственным приложением с приложением Java в различном VM или контексте, или без другого Компонента, то противоположный Компонент или Окно являются нулем. Этой информацией является доступное использование FocusEvent.getOppositeComponent или WindowEvent.getOppositeWindow.

На некоторых платформах не возможно различить противоположный Компонент или Окно, когда изменение фокуса или активации происходит между двумя различными тяжелыми Компонентами. В этих случаях противоположный Компонент или Окно могут быть, устанавливают в NULL на некоторых платформах, и к допустимому ненулевому значению на других платформах. Однако, для фокуса изменяются между двумя легкими Компонентами, которые совместно используют тот же самый тяжелый Контейнер, противоположный Компонент будет всегда устанавливаться правильно. Таким образом чистое приложение Swing может проигнорировать это ограничение платформы при использовании противоположного Компонента изменения фокуса, которое произошло в пределах высокоуровневого Окна.

Временный FocusEvents

FOCUS_GAINED и FOCUS_LOST события отмечаются или как временные или как постоянные.

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

Постоянная передача фокуса обычно происходит как результат пользователя, щелкающего по выбираемому, тяжелому Компоненту, обходу фокуса с клавиатурой или эквивалентным устройством ввода, или от звонка requestFocus() или requestFocusInWindow().

Временная передача фокуса обычно происходит как результат показа Меню или PopupMenu, щелчка или перетаскивания Полосы прокрутки, перемещения Окна, перетаскивая строку заголовка, или делая другое Окно фокусируемое Окно. Отметьте, что на некоторых платформах, эти действия, возможно, не генерируют FocusEvents вообще. На других произойдут временные передачи фокуса.

Когда Компонент получает временное FOCUS_LOST событие, противоположный Компонент события (если кто-либо) может получить временное FOCUS_GAINED событие, но мог также получить постоянное FOCUS_GAINED событие. Показ Меню или PopupMenu, или щелчок или перетаскивание Полосы прокрутки, должны генерировать временное FOCUS_GAINED событие. Изменение фокусируемого Окна, однако, приведет к постоянному FOCUS_GAINED событие для нового владельца фокуса.

Компонентный класс включает разновидности requestFocus и requestFocusInWindow которые берут требуемое временное состояние в качестве параметра. Однако, потому что определение произвольного временного состояния, возможно, не implementable на всех собственных системах управления окнами, корректное поведение для этого метода может быть гарантировано только для легких Компонентов. Этот метод не предназначается для общего использования, но существует вместо этого как рычаг для легких Компонентных библиотек, таких как Swing.

Обход фокуса

Каждый Компонент определяет свой собственный Набор ключей обхода фокуса для данной работы обхода фокуса. Компонентная поддержка разделяет Наборы ключей для прямого и обратного обхода, и также для обхода один цикл обхода фокуса. Контейнеры, которые являются корнями цикла фокуса также, поддерживают ряд ключей для обхода вниз один цикл обхода фокуса. Если Набор явно не определяется для Компонента, что Компонент рекурсивно наследовал Набор от своего родителя, и в конечном счете от набора по умолчанию всего контекста на токе KeyboardFocusManager.

Используя AWTKeyStroke API, клиентский код может определить на который из двух определенных KeyEvents, KEY_PRESSED или KEY_RELEASED, работа обхода фокуса произойдет. Независимо от которого KeyEvent определяется, однако, весь KeyEvents, связанный с ключом обхода фокуса, включая связанное KEY_TYPED событие, будет использовано, и не будет диспетчеризировано никакому Компоненту. Это - ошибка периода выполнения, чтобы определить a KEY_TYPED событие как отображающийся на работу обхода фокуса, или отобразить то же самое событие на многократные операции обхода фокуса для любого определенного Компонента или для a KeyboardFocusManager's значения по умолчанию.

Ключи обхода фокуса по умолчанию являются зависящими от реализации. Sun рекомендует, чтобы все реализации для определенной собственной платформы использовали те же самые ключи. Для Windows и Unix, рекомендации:

Компоненты могут включить и отключить все свои ключи обхода фокуса, в массе используя Component.setFocusTraversalKeysEnabled. Когда ключи обхода фокуса отключаются, Компонент получает весь KeyEvents для тех ключей. Когда ключи обхода фокуса включаются, Компонент никогда не получает KeyEvents для ключей обхода; вместо этого, KeyEvents автоматически отображаются, чтобы фокусировать операции обхода.

Для нормального прямого и обратного обхода реализация фокуса AWT определяет который Компонент фокусироваться затем основанный на FocusTraversalPolicy из корня цикла фокуса владельца фокуса или провайдера политики обхода фокуса. Если владелец фокуса является корнем цикла фокуса, то это может быть неоднозначно, относительно которого Компоненты представляют следующие и предыдущие Компоненты, чтобы фокусироваться во время нормального обхода фокуса. Таким образом, ток KeyboardFocusManager поддерживает ссылку на "текущий" корень цикла фокуса, который является глобальной переменной через все контексты. Текущий корень цикла фокуса используется, чтобы разрешить неоднозначность.

Для обхода-цикла владелец фокуса устанавливается в текущий корень цикла фокуса владельца фокуса, и текущий корень цикла фокуса устанавливается в новый корень цикла фокуса владельца фокуса. Если, однако, текущий корень цикла фокуса владельца фокуса является высокоуровневым окном, то владелец фокуса устанавливается в компонент корня цикла фокуса по умолчанию фокусироваться, и текущий корень цикла фокуса неизменен.

Для обхода периода упадка, если текущий владелец фокуса является корнем цикла фокуса, то владелец фокуса устанавливается в компонент владельца текущего фокуса по умолчанию фокусироваться, и текущий корень цикла фокуса устанавливается в текущего владельца фокуса. Если текущий владелец фокуса не является корнем цикла фокуса, то никакая работа обхода фокуса не происходит.

FocusTraversalPolicy

A FocusTraversalPolicy определяет порядок, в котором пересекаются Компоненты в пределах определенного корня цикла фокуса или провайдера политики обхода фокуса. Экземпляры FocusTraversalPolicy может быть совместно использован через Контейнеры, позволяя те Контейнеры реализовать ту же самую политику обхода. FocusTraversalPolicies не должны быть повторно инициализированы, когда иерархия цикла обхода фокуса изменяется.

Каждый FocusTraversalPolicy должен определить следующие пять алгоритмов:

  1. Учитывая фокус цикл базируются и Компонент в том цикле, следующий Компонент после a.
  2. Учитывая фокус цикл базируются и Компонент в том цикле, предыдущий Компонент прежде a.
  3. Учитывая корень цикла фокуса, "первый" Компонент в том цикле. "Первым" Компонентом является Компонент, чтобы фокусироваться, когда обход переносится в прямом направлении.
  4. Учитывая корень цикла фокуса, "последний" Компонент в том цикле. "Последним" Компонентом является Компонент, чтобы фокусироваться, когда обход переносится в обратном направлении.
  5. Учитывая корень цикла фокуса, Компонент "по умолчанию" в том цикле. Компонент "по умолчанию" будет первым, чтобы получить фокус, пересекая вниз в новый цикл обхода фокуса. Это может быть тем же самым как "первым" Компонентом, но не должно быть.

A FocusTraversalPolicy май дополнительно обеспечивает алгоритм для следующего:

Учитывая Окно, "начальный" Компонент в том Окне. Начальный Компонент будет первым, чтобы получить фокус, когда Окно будет сначала сделано видимым. По умолчанию это - то же самое как Компонент "по умолчанию".
Кроме того, Swing обеспечивает подкласс FocusTraversalPolicy, InternalFrameFocusTraversalPolicy, который позволяет разработчикам обеспечивать алгоритм для следующего:
Данный a JInternalFrame, "начальный" Компонент в этом JInternalFrame. Начальный Компонент является первым, чтобы получить фокус когда JInternalFrame сначала выбирается. По умолчанию это - то же самое как JInternalFrame's Компонент по умолчанию, чтобы фокусироваться.
A FocusTraversalPolicy устанавливается на Контейнере, используя Контейнер.setFocusTraversalPolicy. Если политика явно не устанавливается, то Контейнер наследовал свою политику от его самого близкого корневого циклом фокусом предка. Верхние уровни инициализируют свои политики обхода фокуса, используя политику значения по умолчанию контекста. Политика значения по умолчанию контекста устанавливается при использовании KeyboardFocusManager. setDefaultFocusTraversalPolicy.

AWT обеспечивает два стандарта FocusTraversalPolicy реализации для использования клиентским кодом.

  1. ContainerOrderFocusTraversalPolicy: Выполняет итерации через Компоненты в цикле обхода фокуса в порядке, они были добавлены к их Контейнерам. Каждый Компонент тестируется на пригодность, используя принять (Компонент) метод. По умолчанию Компонент пригоден, только если это является видимым, визуализуемым, включенное, и focusable.
  2. По умолчанию ContainerOrderFocusTraversalPolicy неявно передает период упадка фокуса. Таким образом, во время нормального прямого обхода фокуса Компонент, пересеченный после того, как, корнем цикла фокуса будет Компонент корня цикла фокуса по умолчанию, чтобы фокусироваться, независимо от того, является ли корень цикла фокуса проходимым или непроходимым Контейнером (см. рис. 1,2 ниже). Такое поведение предоставляет обратной совместимости приложения, разработанные без понятия - и обход периода упадка.
  3. DefaultFocusTraversalPolicy: Подкласс ContainerOrderFocusTraversalPolicy который пересматривает фитнес-тест. Если клиентский код явно установил focusability Компонента любым переопределением Component.isFocusTraversable() или Component.isFocusable(), или вызывая Component.setFocusable(boolean), тогда a DefaultFocusTraversalPolicy ведет себя точно как a ContainerOrderFocusTraversalPolicy. Если, однако, Компонент полагается на значение по умолчанию focusability, то a DefaultFocusTraversalPolicy отклонит все Компоненты с коллегами non-focusable.
    focusability коллеги является зависящим от реализации. Sun рекомендует, чтобы все реализации для определенной собственной платформы создали коллеги с тем же самым focusability. Рекомендации для Windows и Unix состоят в том, что у Холстов, Меток, Панелей, Полос прокрутки, ScrollPanes, Windows, и легких Компонентов есть коллеги non-focusable, и у всех других Компонентов есть коллеги focusable. Эти рекомендации используются на солнце реализации AWT. Отметьте, что focusability коллеги Компонента отличается от, и не воздействует, focusability Компонента непосредственно.

Swing обеспечивает две дополнительных, стандартных реализации FocusTraversalPolicy для использования клиентским кодом. Каждой реализацией является InternalFrameFocusTraversalPolicy.

  1. SortingFocusTraversalPolicy: Определяет порядок обхода, сортируя Компоненты цикла обхода фокуса, основанного на данном Компараторе. Каждый Компонент тестируется на пригодность, используя принять (Компонент) метод. По умолчанию Компонент пригоден, только если это является видимым, визуализуемым, включенное, и focusable.
  2. По умолчанию SortingFocusTraversalPolicy неявно передает период упадка фокуса. Таким образом, во время нормального прямого обхода фокуса Компонент, пересеченный после того, как, корнем цикла фокуса будет Компонент корня цикла фокуса по умолчанию, чтобы фокусироваться, независимо от того, является ли корень цикла фокуса проходимым или непроходимым Контейнером (см. рис. 1,2 ниже). Такое поведение предоставляет обратной совместимости приложения, разработанные без понятия - и обход периода упадка.
  3. LayoutFocusTraversalPolicy: подкласс SortingFocusTraversalPolicy, который Компоненты видов, основанные на их размере, позиции, и ориентации. Основанный на их размере и позиции, Компоненты примерно категоризируются в строки и столбцы. Для Контейнера с горизонтальной ориентацией столбцы работают слева направо или справа налево, и строки, выполненные от начала до конца. Для Контейнера с вертикальной ориентацией столбцы, выполненные от начала до конца и строки, работают слева направо или справа налево. Все столбцы подряд полностью пересекаются прежде, чем продолжиться к следующей строке.
    Кроме того, фитнес-тест расширяется, чтобы исключить JComponents, которые имеют или наследовали пустой InputMaps.

Данные ниже показывают неявную передачу фокуса:
Неявная передача фокуса.
Примите следующее:

Приложения Swing, или смешанные приложения Swing/AWT, то использование один из стандартного взгляда и чувств, или любого другого стили, полученного из BasicLookAndFeel, будут использовать LayoutFocusTraversalPolicy для всех Контейнеров по умолчанию.

Все другие приложения, включая чистые приложения AWT, будут использовать DefaultFocusTraversalPolicy по умолчанию.

Провайдеры Политики Обхода фокуса

У Контейнера, который не является корнем цикла фокуса, есть опция, чтобы предоставить собственному FocusTraversalPolicy. Чтобы сделать так, нужно установить свойство провайдера политики обхода фокуса Контейнера в true со звонком

Чтобы определить, является ли Контейнер провайдером политики обхода фокуса, следующий метод должен использоваться: Если свойство провайдера политики обхода фокуса устанавливается на корне цикла фокуса, это не считают провайдером политики обхода фокуса и ведет себя точно так же как любой другой корень цикла фокуса.

Основное различие между корнями цикла фокуса и провайдерами политики обхода фокуса - то, что последние позволяют фокусу вводить и оставлять их так же, как все другие Контейнеры. Однако, дочерние элементы в провайдере политики обхода фокуса пересекаются в порядке, определенном FocusTraversalPolicy провайдера. Чтобы позволить провайдерам политики обхода фокуса вести себя этот путь, FocusTraversalPolicies обрабатывают их следующим способом:

Программируемый Обход

В дополнение к инициируемому пользователем обходу фокуса клиентский код может инициировать работу обхода фокуса программно. К клиентскому коду программируемые обходы неотличимы от инициируемых пользователем обходов. Привилегированный способ инициировать программируемый обход состоит в том, чтобы использовать один из следующих методов на KeyboardFocusManager:

Каждый из этих методов инициирует работу обхода с текущим владельцем фокуса. Если нет в настоящий момент никакого владельца фокуса, то никакая работа обхода не происходит. Кроме того, если владелец фокуса не является корнем цикла фокуса, то downFocusCycle () не выполняет работы обхода.

KeyboardFocusManager также поддерживает следующие разновидности этих методов:

Каждый из этих методов инициирует работу обхода с указанным Компонентом, а не владельцем фокуса. Таким образом, обход происходит, как если бы указанный Компонент является владельцем фокуса, хотя это не должно быть.

Альтернатива, но эквивалентный, API определяются на Компоненте и Контейнерных классах непосредственно:

Как с KeyboardFocusManager разновидности, каждый из этих методов инициирует работу обхода, как если бы Компонент является владельцем фокуса, хотя это не должно быть.

Также отметьте, что сокрытие или отключение владельца фокуса, прямо или косвенно через предка, или создание невизуализуемого владельца фокуса или non-focusable, инициируют автоматический, прямой обход фокуса. В то время как сокрытие любого предка, легкого веса или тяжеловеса, будет всегда косвенно скрывать свои дочерние элементы, только отключая предка в тяжелом весе отключит его дочерние элементы. Таким образом отключение легкого предка владельца фокуса автоматически не инициирует обход фокуса.

Если клиентский код инициирует обход фокуса, и нет никакого другого Компонента, чтобы фокусироваться, то владелец фокуса остается неизменным. Если клиентский код инициирует автоматический обход фокуса, скрывая владельца фокуса, прямо или косвенно, или делая невизуализуемого владельца фокуса или non-focusable, и нет никакого другого Компонента, чтобы фокусироваться, то глобальный владелец фокуса очищается. Если клиентский код инициирует автоматический обход фокуса, отключая владельца фокуса, прямо или косвенно, и нет никакого другого Компонента, чтобы фокусироваться, то владелец фокуса остается неизменным.

Focusability

focusable Компонент может стать владельцем фокуса ("focusability") и участвует в обходе клавиатурного фокуса ("фокусируют traversability") с FocusTraversalPolicy. Нет никакого разделения этих двух понятий; Компонент должен или быть и focusable и проходимым фокусом, или ни одним. Компонент выражает это состояние через isFocusable () метод. По умолчанию все Компоненты возвращают true от этого метода. Клиентский код может изменить это значение по умолчанию, вызывая Component.setFocusable (булевская переменная).

Windows Focusable

Чтобы поддерживать окна палитры и ввести методы, клиентский код может препятствовать тому, чтобы Окно стало фокусируемым Окном. Транзитивностью это предотвращает Окно или любого из его потомков от становления владельцем фокуса. Windows Non-focusable может все еще принадлежать Windows, которые являются focusable. По умолчанию каждый Фрейм и Диалоговое окно являются focusable. Каждое Окно, которое не является Фреймом или Диалоговым окном, но чей самый близкий Фрейм обладания или Диалоговое окно показывают на экране, и у которого есть по крайней мере один Компонент в его цикле обхода фокуса, также focusable по умолчанию. Чтобы сделать Окно non-focusable, используйте Window.setFocusableWindowState (ложь).

Если Окно является non-focusable, это ограничение осуществляется когда KeyboardFocusManager видит a WINDOW_GAINED_FOCUS событие для Окна. В этой точке отклоняется изменение фокуса, и фокус сбрасывается к различному Окну. Схема восстановления отклонения является тем же самым как будто a VetoableChangeListener отклоненный изменение фокуса. См. Фокус и VetoableChangeListener.

Поскольку новая реализация фокуса требует, чтобы KeyEvents, предназначенные для Окна или его потомков, были проксированы через дочерний элемент владельца Окна, и потому что этот прокси должен быть отображен на X11, чтобы получить события, Окно, самый близкий Фрейм обладания которого или Диалоговое окно не показывают, никогда не могло получать KeyEvents на X11. Чтобы поддерживать это ограничение, мы сделали различие между "окном Окна focusability" и его "окном focusability состояние". Состояние focusability Окна объединяется с состоянием показа самого близкого Фрейма обладания Окна или Диалогового окна, чтобы определить focusability Окна. По умолчанию, весь Windows имеют focusability состояние истины. Установка состояния focusability Окна ко лжи гарантирует, что это не будет становиться фокусируемым Окном независимо от состояния показа его самого близкого Фрейма обладания или Диалогового окна.

Swing позволяет приложениям создавать JWindows с нулевыми владельцами. Swing создает весь такой JWindows так, чтобы они принадлежали частному, скрытому Фрейму. Поскольку состояние показа этого Фрейма всегда будет ложью, JWindow созданное желание, нулевым владельцем никогда не может быть фокусируемое Окно, даже если у этого есть Окно focusability состояние истины.

Если фокусируемое Окно будет сделано non-focusable, то AWT попытается фокусировать последний раз фокусируемый Компонент владельца Окна. Владелец Окна таким образом станет новым фокусируемым Окном. Если владельцем Окна будет также non-focusable Окно, то запрос на изменение фокуса продолжит иерархию владения рекурсивно. С тех пор не все платформы поддерживают изменения фокуса перекрестного окна (см. Запрос Фокуса), возможно, что все такие запросы на изменение фокуса перестанут работать. В этом случае глобальный владелец фокуса будет очищен, и фокусируемое Окно останется неизменным.

Запрос Фокуса

Компонент может запросить, чтобы это стало владельцем фокуса, вызывая Component.requestFocus(). Это инициирует постоянную передачу фокуса в Компонент, только если Компонент является визуализуемым, focusable, видимым, и все его предки (за исключением высокоуровневого Окна) видимы. Запрос будет сразу отрицаться, если какое-либо из этих условий не будут соблюдать. Отключенный Компонент может быть владельцем фокуса; однако, в этом случае, весь KeyEvents будет отброшен.

Запрос будет также отрицаться, если высокоуровневым Окном Компонента не будет фокусируемое Окно, и платформа не поддерживает запрос фокуса через Windows. Если запрос отрицается по этой причине, запрос помнят и будет предоставлен, когда Окно позже фокусируется пользователем. Иначе, запрос на изменение фокуса изменяет фокусируемое Окно также.

Нет никакого способа определить синхронно, предоставили ли запрос на изменение фокуса. Вместо этого клиентский код должен установить FocusListener на Компоненте и наблюдать за поставкой a FOCUS_GAINED событие. Клиентский код не должен предположить, что Компонент является владельцем фокуса, пока это не получает это событие. Событие может или не может быть поставлено прежде requestFocus() возвраты. Разработчики не должны принять одно поведение или другой.

AWT поддерживает ввод с опережением, если все запросы на изменение фокуса делаются на EventDispatchThread. Если клиентский код запросит изменение фокуса, и AWT решает, что этот запрос могла бы предоставить собственная система управления окнами, то AWT уведомит текущий KeyboardFocusManager, который является, должен ставить в очередь весь KeyEvents с меткой времени позже чем то из события, в настоящий момент обрабатываемого. Эти KeyEvents не будут диспетчеризированы, пока новый Компонент не становится владельцем фокуса. AWT отменит задержанный запрос диспетчеризации, если изменение фокуса не успешно выполнится на собственном уровне, если коллега Компонента располагается, или если на изменение фокуса накладывает вето VetoableChangeListener. KeyboardFocusManagers не обязаны поддерживать ввод с опережением, если запрос на изменение фокуса делается из потока кроме EventDispatchThread.

Поскольку Component.requestFocus() не может последовательно реализовываться через платформы, разработчики поощряются использовать Component.requestFocusInWindow() вместо этого. Этот метод отрицает передачи фокуса перекрестного окна на всех платформах автоматически. Устраняя единственный специфичный для платформы элемент передачи фокуса, этот метод достигает непротиворечивого межплатформенного поведения.

Кроме того, requestFocusInWindow() возвращает булево значение. Если 'false' будет возвращен, то запрос, как гарантируют, перестанет работать. Если 'true' будет возвращен, то запрос успешно выполнится, если на это не наложат вето, или экстраординарное событие, такое как избавление от коллеги Компонента, имеет место прежде, чем запрос может предоставить собственная система управления окнами. Снова, в то время как возвращаемое значение 'истины' указывает, что запрос, вероятно, успешно выполнится, разработчики никогда не должны предполагать, что этот Компонент является владельцем фокуса, пока этот Компонент не получает a FOCUS_GAINED событие.

Если клиентский код не хочет, чтобы Компонент в приложении был владельцем фокуса, это может вызвать метод KeyboardFocusManager. clearGlobalFocusOwner() на токе KeyboardFocusManager. Если там будет существовать владелец фокуса, когда этот метод вызовут, то владелец фокуса получит постоянное FOCUS_LOST событие. После этой точки реализация фокуса AWT отбросит весь KeyEvents, пока пользовательский или клиентский код явно не установит фокус в Компонент.

Компонентный класс также поддерживает разновидности requestFocus и requestFocusInWindow это позволяет клиентскому коду определять временное состояние. См. Временный FocusEvents

Фокус и PropertyChangeListener

Клиентский код может слушать изменения в состоянии фокуса всего контекста, или к изменениям в связанном с фокусом состоянии в Компонентах, через PropertyChangeListeners.

KeyboardFocusManager поддерживает следующие свойства:

  1. focusOwner: владелец фокуса
  2. focusedWindow: фокусируемое Окно
  3. activeWindow: активное окно
  4. defaultFocusTraversalPolicy: политика обхода фокуса по умолчанию
  5. forwardDefaultFocusTraversalKeys: Набор значения по умолчанию FORWARD_TRAVERSAL_KEYS
  6. backwardDefaultFocusTraversalKeys: Набор значения по умолчанию BACKWARD_TRAVERSAL_KEYS
  7. upCycleDefaultFocusTraversalKeys: Набор значения по умолчанию UP_CYCLE_TRAVERSAL_KEYS
  8. downCycleDefaultFocusTraversalKeys: Набор значения по умолчанию DOWN_CYCLE_TRAVERSAL_KEYS
  9. currentFocusCycleRoot: текущий корень цикла фокуса

A PropertyChangeListener установленный на токе KeyboardFocusManager будет только видеть эти изменения в пределах KeyboardFocusManager's контекст, даже при том, что владелец фокуса, фокусировал Окно, активное окно, и текущий корень цикла фокуса включает глобальное состояние фокуса, совместно использованное всеми контекстами. Мы полагаем, что это менее навязчиво чем требование, чтобы клиентский код передал проверку защиты прежде, чем установить a PropertyChangeListener.

Компонент поддерживает следующие связанные с фокусом свойства:

  1. focusable: focusability Компонента
  2. focusTraversalKeysEnabled: ключи обхода фокуса Компонента, включенные состояние
  3. forwardFocusTraversalKeys: Набор Компонента FORWARD_TRAVERSAL_KEYS
  4. backwardFocusTraversalKeys: Набор Компонента BACKWARD_TRAVERSAL_KEYS
  5. upCycleFocusTraversalKeys: Набор Компонента UP_CYCLE_TRAVERSAL_KEYS

В дополнение к свойствам Component Контейнер поддерживает следующие связанные с фокусом свойства:

  1. downCycleFocusTraversalKeys: Набор Контейнера DOWN_CYCLE_TRAVERSAL_KEYS
  2. focusTraversalPolicy: политика обхода фокуса Контейнера
  3. focusCycleRoot: корневое циклом фокусом состояние Контейнера

В дополнение к свойствам Container Окно поддерживает следующее связанное с фокусом свойство:

  1. focusableWindow: focusable Статус окна Окна

Также отметьте это a PropertyChangeListener установленный на Окне никогда не будет видеть a PropertyChangeEvent для focusCycleRoot свойство. Окно всегда является корнем цикла фокуса; это свойство не может измениться.

Фокус и VetoableChangeListener

KeyboardFocusManager также поддерживает VetoableChangeListeners для следующих свойств:

  1. "focusOwner": владелец фокуса
  2. "focusedWindow": фокусируемое Окно
  3. "activeWindow": активное окно
Если VetoableChangeListener накладывает вето на фокус или изменение активации, бросая PropertyVetoException, изменение прерывается. Любой VetoableChangeListeners, который уже одобрил изменение, асинхронно получит PropertyChangeEvents, указывающий на возвращение состояния к предыдущему значению.

VetoableChangeListeners уведомляются относительно изменения состояния прежде, чем изменение будет отражено в KeyboardFocusManager. Наоборот, PropertyChangeListeners уведомляются после того, как изменение отражается. Из этого следует, что весь VetoableChangeListeners будет уведомлен перед любым PropertyChangeListener.

VetoableChangeListeners должен быть идемпотентом, и должен наложить вето и на потерю и на события усиления для определенного изменения фокуса (например, оба FOCUS_LOST и FOCUS_GAINED). Например, если a VetoableChangeListener вето a FOCUS_LOST событие, a KeyboardFocusManager не обязан искать EventQueue и удалите связанное ожидание FOCUS_GAINED событие. Вместо этого KeyboardFocusManager свободно попытаться диспетчеризировать это событие, и это - ответственность VetoableChangeListener наложить вето на это также. Кроме того, во время обработки FOCUS_GAINED событие, KeyboardFocusManager может попытаться повторно синхронизировать глобальное состояние фокуса, синтезируя другого FOCUS_LOST событие. На это событие нужно наложить вето так же, как первое FOCUS_LOST событие было.

A KeyboardFocusManager возможно, не содержит блокировок, уведомляя PropertyChangeListeners изменения состояния. Это требование ослабляется для VetoableChangeListeners, как бы то ни было. Поэтому, клиент-definied VetoableChangeListeners должен избежать получать дополнительные блокировки внутри vetoableChange(PropertyChangeEvent) поскольку это может привести к мертвой блокировке. Если изменение фокуса или активации будет отклонено, то KeyboardFocusManager будет инициировать восстановление отклонения следующим образом:

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

Z-порядок

На некоторых собственных системах управления окнами Z-порядок Окна может влиять на свой фокусируемый, или активные (если применимый) утверждают. На Microsoft Windows самым верхним Окном является естественно фокусируемое Окно также. Однако, на Солярисе, много менеджеров окон используют модель точки к фокусу, которая игнорирует Z-порядок в определении фокусируемого Окна. Фокусируясь или активируя Windows, AWT придерживается требований UI собственной платформы. Поэтому, поведение фокуса методов Z-order-related, таких как:

зависимо от платформы. В JDK 1.4, поведение этих методов на Microsoft Windows и Солярисе следующие:

Замена DefaultKeyboardFocusManager

KeyboardFocusManagers являются сменными на уровне контекста браузера. Клиентский код может разделить на подклассы KeyboardFocusManager или DefaultKeyboardFocusManager изменить способ, которым WindowEvents, связанные с фокусом, FocusEvents, и KeyEvents, обрабатываются и диспетчеризируются, и исследовать и изменить глобальное состояние фокуса. Пользовательское KeyboardFocusManager может также отклонить изменения фокуса на более фундаментальном уровне тогда, FocusListener или WindowListener когда-либо могли.

Давая разработчику окончательный контроль над моделью фокуса, заменяя все KeyboardFocusManager трудный процесс, требующий полного понимания равноправного уровня фокуса. К счастью, большинство приложений не нуждается в этом большом управлении. Разработчики поощряются использовать KeyEventDispatchers, KeyEventPostProcessors, FocusTraversalPolicies, VetoableChangeListeners, и другие понятия, обсужденные в этом документе прежде, чем обратиться к полной замене KeyboardFocusManager.

Сначала отметьте, что, потому что беспрепятственный доступ к Компонентам в других контекстах представляет дыру в системе безопасности, SecurityManager должен предоставить новое разрешение, "replaceKeyboardFocusManager", прежде, чем клиентскому коду разрешат заменить KeyboardFocusManager с произвольным экземпляром подкласса. Из-за проверки защиты, заменяя KeyboardFocusManager не опция для приложений, которые будут развернуты в средах с SecurityManager, таких как апплеты в браузере.

После того, как установленный, a KeyboardFocusManager у экземпляра есть доступ к глобальному состоянию фокуса через ряд защищенных функций. KeyboardFocusManager может только вызвать эти функции, если это устанавливается в контексте вызывающего потока. Это гарантирует, что вредоносный код не может обойти проверку защиты в KeyboardFocusManager.setCurrentFocusManager. A KeyboardFocusManager должен всегда работать с глобальным состоянием фокуса вместо состояния фокуса контекста. Отказ сделать это приведет к неправильному поведению KeyboardFocusManager.

Основная ответственность a KeyboardFocusManager диспетчеризирование следующих событий:

Равноправный уровень обеспечит KeyboardFocusManager со всеми вышеупомянутыми событиями кроме WINDOW_ACTIVATED и WINDOW_DEACTIVATED. KeyboardFocusManager должен синтезировать WINDOW_ACTIVATED и WINDOW_DEACTIVATED события, когда соответствующий и предназначаются для них соответственно.

KeyboardFocusManager возможно, должен перенастроить события, обеспеченные равноправным уровнем для его собственного понятия владельца фокуса или фокусируемого Окна:

A KeyboardFocusManager должен гарантировать надлежащее упорядочивание события, и 1 к 1 корреспонденция между событием и его противоположным типом события. Равноправный уровень не делает ни одной из этих гарантий. Например, для равноправного уровня возможно отправить a FOCUS_GAINED событие прежде a WINDOW_GAINED_FOCUS событие. KeyboardFocusManager ответственно за обеспечение что WINDOW_GAINED_FOCUS событие диспетчеризируется перед FOCUS_GAINED событие.

Прежде, чем повторно диспетчеризировать событие через KeyboardFocusManager. redispatchEvent, a KeyboardFocusManager должен попытаться обновить глобальное состояние фокуса. Как правило, это делается, используя один из KeyboardFocusManager.setGlobal* методы; однако, реализация свободна реализовать свои собственные методы. После попытки обновления, KeyboardFocusManager должен проверить, что глобальное изменение состояния фокуса не было отклонено. Отклонение обнаруживается когда звонок в соответствие getGlobal* метод возвращает значение, отличающееся чем значение только набор. Отклонения происходят в трех стандартных случаях:

Определенные клиентом реализации KeyboardFocusManager может скорректировать набор передач фокуса, которые отклоняются, переопределяя средство доступа и мутаторные методы для глобального состояния фокуса.

Если запрос, чтобы изменить глобальное состояние фокуса отклоняется, KeyboardFocusManager должен отбросить событие, которое запрашивало запрос на изменение фокуса. Компонент, к которому было предназначено событие, не должен получить событие.

KeyboardFocusManager как также ожидают, будет инициировать восстановление отклонения как обрисовано в общих чертах в Фокусе и VetoableChangeListener.

Наконец, KeyboardFocusManager должен обработать следующий набор особых случаев:

Несовместимости с Предыдущими Выпусками

Межплатформенные изменения:

  1. Фокус по умолчанию traversability для всех Компонентов является теперь 'истиной'. Ранее, некоторые Компоненты (в частности все легкие веса), имел фокус по умолчанию traversability 'лжи'. Отметьте это несмотря на это изменение, однако, DefaultFocusTraversalPolicy поскольку все Контейнеры AWT сохранят порядок обхода предыдущих выпусков.
  2. Запрос, чтобы фокусировать проходимый нефокус (то есть, non-focusable) Компонент будет отрицаться. Ранее, такие запросы предоставили.
  3. Window.toFront() и Window.toBack() теперь не выполните работу, если Окно не видимо. Ранее, поведение было зависимо от платформы.
  4. KeyListeners, установленный на Components больше не будет видеть KeyEvents, что карта, чтобы фокусировать операции обхода, и Component.handleEvent() больше не будет вызван для таких событий. Ранее, Компоненты AWT видели эти события и имели возможность использовать их перед AWT инициируемый обход фокуса. Код, который требует этой функциональности, должен вместо этого отключить обход фокуса, включает Components и дескриптор фокусируют обход непосредственно. Поочередно, код может использовать AWTEventListener или KeyEventDispatcher предварительно слушать все KeyEvents.

Изменяется определенный для Microsoft Windows:

  1. Window.toBack() изменяет фокусируемое Окно на самое верхнее Окно после изменения Z-порядка.
  2. requestFocus() теперь позволяет запросы на изменение фокуса перекрестного окна во всех случаях. Ранее, запросы предоставили для тяжеловесов, но отрицались для легких весов.