Spec-Zone .ru
спецификации, руководства, описания, API
|
До 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, который обеспечивает ряд API для клиентского кода, чтобы запросить о текущем состоянии фокуса, начатых изменениях фокуса, и диспетчеризации события фокуса значения по умолчанию замены с пользовательским диспетчером. Клиенты могут запросить о состоянии фокуса непосредственно, или могут зарегистрировать PropertyChangeListener, который получит PropertyChangeEvents, когда изменение к состоянию фокуса произойдет.
KeyboardFocusManager представляет следующие основные понятия и их терминологию:
setFocusTraversalPolicyProvider
на Контейнере. Каждое Окно и JInternalFrame являются, по умолчанию, "корнем цикла фокуса". Если это - единственный корень цикла фокуса, то все его focusable потомки должны быть в его цикле фокуса, и его политика обхода фокуса должна осуществить это, они, удостоверяясь, что все будут достигнуты во время прямого нормального (или назад) обход. Если, с другой стороны, Окно или JInternalFrame имеет потомков, которые являются также корнями цикла фокуса, то каждый такой потомок является элементом двух циклов фокуса: тот, что это - корень, и то его самого близкого корневого циклом фокусом предка. Чтобы пересечь focusable компоненты, принадлежащие циклу фокуса такого "порожденного" корня цикла фокуса, первые пересечения (вперед или назад), чтобы достигнуть потомка, и затем использует "вниз цикл" работа, чтобы достигнуть, поочередно, ее потомков.
Вот пример:
Примите следующее:
Window
, что означает, что это должен быть корень цикла фокуса. Container
s, которые являются корнями цикла фокуса. Container
это не корень цикла фокуса. Component
s. KeyboardFocusManager
абстрактный класс. AWT обеспечивает реализацию по умолчанию в DefaultKeyboardFocusManager
класс.
Некоторые апплеты раздела браузеров в различных кодовых базах в отдельные контексты, и устанавливают стены между этими контекстами. Каждый поток и каждый Компонент связываются с определенным контекстом и не могут вмешаться в потоки или Компоненты доступа в других контекстах. В таком сценарии будет один KeyboardFocusManager на контекст. Другие браузеры помещают все апплеты в тот же самый контекст, подразумевая, что будет только единственный, глобальный KeyboardFocusManager для всех апплетов. Это поведение является зависящим от реализации. Консультируйтесь с документацией своего браузера для получения дополнительной информации. Независимо от того, сколькими контексты там могут быть, однако, никогда не может быть больше чем одного владельца фокуса, фокусируемого Окна, или активного окна, на ClassLoder.
В то время как 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, и подобные ограничения применяются к его использованию в той емкости.
AWT определяет следующие шесть типов события, центральных к модели фокуса в два отличающийся java.awt.event
классы:
WindowEvent.WINDOW_ACTIVATED
: Это событие диспетчеризируется Фрейму или Диалоговому окну (но никогда Окно, которое не является Фреймом или Диалоговым окном), когда это становится активным окном. WindowEvent.WINDOW_GAINED_FOCUS
: Это событие диспетчеризируется Окну, когда это становится фокусируемым Окном. Только Windows focusable может получить это событие. FocusEvent.FOCUS_GAINED
: Это событие диспетчеризируется Компоненту, когда это становится владельцем фокуса. Только Компоненты focusable могут получить это событие. FocusEvent.FOCUS_LOST
: Это событие диспетчеризируется Компоненту, когда это больше не владелец фокуса. WindowEvent.WINDOW_LOST_FOCUS
: Это событие диспетчеризируется Окну, когда это больше не фокусируемое Окно. WindowEvent.WINDOW_DEACTIVATED
: Это событие диспетчеризируется Фрейму или Диалоговому окну (но никогда Окно, которое не является Фреймом или Диалоговым окном), когда это больше не активное окно. Если фокус не будет в приложении java, и пользователь щелкает по focusable дочернему элементу Компоненте неактивного Фрейма b, то следующие события будут диспетчеризированы и обработаны в порядке:
WINDOW_ACTIVATED
событие. WINDOW_GAINED_FOCUS
событие. FOCUS_GAINED
событие. FOCUS_LOST
событие. WINDOW_LOST_FOCUS
событие. WINDOW_DEACTIVATED
событие. WINDOW_ACTIVATED
событие. WINDOW_GAINED_FOCUS
событие. FOCUS_GAINED
событие. Кроме того, каждый тип события будет диспетчеризирован в 1 к 1 корреспонденции ее противоположному типу события. Например, если Компонент получает a FOCUS_GAINED
событие, ни в коем случае не может это никогда принимать другого FOCUS_GAINED
событие без вмешательства FOCUS_LOST
событие.
Наконец, важно отметить, что эти события поставляются для информационных целей только. Невозможно, например, предотвратить поставку ожидания FOCUS_GAINED
событие, запрашивая фокус назад к Компонентной потере фокусируется, обрабатывая предыдущее FOCUS_LOST
событие. В то время как клиентский код может обратиться с такой просьбой, ожиданием FOCUS_GAINED
будет все еще поставлен, сопровождаться позже событиями, возвращающими фокус исходному владельцу фокуса.
Если абсолютно необходимо подавить FOCUS_GAINED
событие, клиентский код может установить a VetoableChangeListener
который отклоняет изменение фокуса. См. Фокус и VetoableChangeListener.
Каждое событие включает информацию о "противоположном" Компоненте или Окне, включенном в изменение активации или фокус. Например, для a FOCUS_GAINED
событие, противоположным Компонентом является Компонент, который потерял фокус. Если изменение фокуса или активации происходит с собственным приложением с приложением Java в различном VM или контексте, или без другого Компонента, то противоположный Компонент или Окно являются нулем. Этой информацией является доступное использование FocusEvent.getOppositeComponent
или WindowEvent.getOppositeWindow
.
На некоторых платформах не возможно различить противоположный Компонент или Окно, когда изменение фокуса или активации происходит между двумя различными тяжелыми Компонентами. В этих случаях противоположный Компонент или Окно могут быть, устанавливают в NULL на некоторых платформах, и к допустимому ненулевому значению на других платформах. Однако, для фокуса изменяются между двумя легкими Компонентами, которые совместно используют тот же самый тяжелый Контейнер, противоположный Компонент будет всегда устанавливаться правильно. Таким образом чистое приложение Swing может проигнорировать это ограничение платформы при использовании противоположного Компонента изменения фокуса, которое произошло в пределах высокоуровневого Окна.
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, рекомендации:
CTRL-TAB
на KEY_PRESSED
TAB
на KEY_PRESSED
и CTRL-TAB
на KEY_PRESSED
CTRL-SHIFT-TAB
на KEY_PRESSED
SHIFT-TAB
на KEY_PRESSED
и CTRL-SHIFT-TAB
на KEY_PRESSED
Компоненты могут включить и отключить все свои ключи обхода фокуса, в массе используя Component.setFocusTraversalKeysEnabled
. Когда ключи обхода фокуса отключаются, Компонент получает весь KeyEvents для тех ключей. Когда ключи обхода фокуса включаются, Компонент никогда не получает KeyEvents для ключей обхода; вместо этого, KeyEvents автоматически отображаются, чтобы фокусировать операции обхода.
Для нормального прямого и обратного обхода реализация фокуса AWT определяет который Компонент фокусироваться затем основанный на FocusTraversalPolicy
из корня цикла фокуса владельца фокуса или провайдера политики обхода фокуса. Если владелец фокуса является корнем цикла фокуса, то это может быть неоднозначно, относительно которого Компоненты представляют следующие и предыдущие Компоненты, чтобы фокусироваться во время нормального обхода фокуса. Таким образом, ток KeyboardFocusManager
поддерживает ссылку на "текущий" корень цикла фокуса, который является глобальной переменной через все контексты. Текущий корень цикла фокуса используется, чтобы разрешить неоднозначность.
Для обхода-цикла владелец фокуса устанавливается в текущий корень цикла фокуса владельца фокуса, и текущий корень цикла фокуса устанавливается в новый корень цикла фокуса владельца фокуса. Если, однако, текущий корень цикла фокуса владельца фокуса является высокоуровневым окном, то владелец фокуса устанавливается в компонент корня цикла фокуса по умолчанию фокусироваться, и текущий корень цикла фокуса неизменен.
Для обхода периода упадка, если текущий владелец фокуса является корнем цикла фокуса, то владелец фокуса устанавливается в компонент владельца текущего фокуса по умолчанию фокусироваться, и текущий корень цикла фокуса устанавливается в текущего владельца фокуса. Если текущий владелец фокуса не является корнем цикла фокуса, то никакая работа обхода фокуса не происходит.
A FocusTraversalPolicy
определяет порядок, в котором пересекаются Компоненты в пределах определенного корня цикла фокуса или провайдера политики обхода фокуса. Экземпляры FocusTraversalPolicy
может быть совместно использован через Контейнеры, позволяя те Контейнеры реализовать ту же самую политику обхода. FocusTraversalPolicies не должны быть повторно инициализированы, когда иерархия цикла обхода фокуса изменяется.
Каждый FocusTraversalPolicy
должен определить следующие пять алгоритмов:
A FocusTraversalPolicy
май дополнительно обеспечивает алгоритм для следующего:
Учитывая Окно, "начальный" Компонент в том Окне. Начальный Компонент будет первым, чтобы получить фокус, когда Окно будет сначала сделано видимым. По умолчанию это - то же самое как Компонент "по умолчанию".Кроме того, Swing обеспечивает подкласс
FocusTraversalPolicy
, InternalFrameFocusTraversalPolicy
, который позволяет разработчикам обеспечивать алгоритм для следующего: Данный aAJInternalFrame
, "начальный" Компонент в этомJInternalFrame
. Начальный Компонент является первым, чтобы получить фокус когдаJInternalFrame
сначала выбирается. По умолчанию это - то же самое какJInternalFrame
's Компонент по умолчанию, чтобы фокусироваться.
FocusTraversalPolicy
устанавливается на Контейнере, используя Контейнер.setFocusTraversalPolicy
. Если политика явно не устанавливается, то Контейнер наследовал свою политику от его самого близкого корневого циклом фокусом предка. Верхние уровни инициализируют свои политики обхода фокуса, используя политику значения по умолчанию контекста. Политика значения по умолчанию контекста устанавливается при использовании KeyboardFocusManager. setDefaultFocusTraversalPolicy
. AWT обеспечивает два стандарта FocusTraversalPolicy
реализации для использования клиентским кодом.
ContainerOrderFocusTraversalPolicy
: Выполняет итерации через Компоненты в цикле обхода фокуса в порядке, они были добавлены к их Контейнерам. Каждый Компонент тестируется на пригодность, используя принять (Компонент) метод. По умолчанию Компонент пригоден, только если это является видимым, визуализуемым, включенное, и focusable. DefaultFocusTraversalPolicy
: Подкласс ContainerOrderFocusTraversalPolicy
который пересматривает фитнес-тест. Если клиентский код явно установил focusability Компонента любым переопределением Component.isFocusTraversable()
или Component.isFocusable()
, или вызывая Component.setFocusable(boolean)
, тогда a DefaultFocusTraversalPolicy
ведет себя точно как a ContainerOrderFocusTraversalPolicy
. Если, однако, Компонент полагается на значение по умолчанию focusability, то a DefaultFocusTraversalPolicy
отклонит все Компоненты с коллегами non-focusable. Swing обеспечивает две дополнительных, стандартных реализации FocusTraversalPolicy для использования клиентским кодом. Каждой реализацией является InternalFrameFocusTraversalPolicy.
Данные ниже показывают неявную передачу фокуса:
Примите следующее:
Приложения Swing, или смешанные приложения Swing/AWT, то использование один из стандартного взгляда и чувств, или любого другого стили, полученного из BasicLookAndFeel, будут использовать LayoutFocusTraversalPolicy для всех Контейнеров по умолчанию.
Все другие приложения, включая чистые приложения AWT, будут использовать DefaultFocusTraversalPolicy
по умолчанию.
У Контейнера, который не является корнем цикла фокуса, есть опция, чтобы предоставить собственному FocusTraversalPolicy. Чтобы сделать так, нужно установить свойство провайдера политики обхода фокуса Контейнера в true
со звонком
Container.setFocusTraversalPolicyProvider(boolean)
Container.isFocusTraversalPolicyProvider()
Основное различие между корнями цикла фокуса и провайдерами политики обхода фокуса - то, что последние позволяют фокусу вводить и оставлять их так же, как все другие Контейнеры. Однако, дочерние элементы в провайдере политики обхода фокуса пересекаются в порядке, определенном FocusTraversalPolicy провайдера. Чтобы позволить провайдерам политики обхода фокуса вести себя этот путь, FocusTraversalPolicies обрабатывают их следующим способом:
FocusTraversalPolicy.getComponentAfter
или FocusTraversalPolicy.getComponentBefore
, next
найденный Компонент first
Компонент провайдера политики обхода фокуса, Компонент после того, как провайдер политики обхода фокуса возвращается previous
найденный Компонент last
Компонент провайдера политики обхода фокуса, Компонент прежде, чем провайдер политики обхода фокуса возвращается FocusTraversalPolicy.getComponentAfter
, FocusTraversalPolicy.getComponentAfter
методом является проходимый Контейнер, и это - провайдер политики обхода фокуса, тогда Компонент по умолчанию этого провайдера возвращается FocusTraversalPolicy.getComponentBefore
, В дополнение к инициируемому пользователем обходу фокуса клиентский код может инициировать работу обхода фокуса программно. К клиентскому коду программируемые обходы неотличимы от инициируемых пользователем обходов. Привилегированный способ инициировать программируемый обход состоит в том, чтобы использовать один из следующих методов на KeyboardFocusManager
:
KeyboardFocusManager.focusNextComponent()
KeyboardFocusManager.focusPreviousComponent()
KeyboardFocusManager.upFocusCycle()
KeyboardFocusManager.downFocusCycle()
Каждый из этих методов инициирует работу обхода с текущим владельцем фокуса. Если нет в настоящий момент никакого владельца фокуса, то никакая работа обхода не происходит. Кроме того, если владелец фокуса не является корнем цикла фокуса, то downFocusCycle () не выполняет работы обхода.
KeyboardFocusManager
также поддерживает следующие разновидности этих методов:
KeyboardFocusManager.focusNextComponent(Component)
KeyboardFocusManager.focusPreviousComponent(Component)
KeyboardFocusManager.upFocusCycle(Component)
KeyboardFocusManager.downFocusCycle(Container)
Альтернатива, но эквивалентный, API определяются на Компоненте и Контейнерных классах непосредственно:
Component.transferFocus()
Component.transferFocusBackward()
Component.transferFocusUpCycle()
Container.transferFocusDownCycle()
KeyboardFocusManager
разновидности, каждый из этих методов инициирует работу обхода, как если бы Компонент является владельцем фокуса, хотя это не должно быть. Также отметьте, что сокрытие или отключение владельца фокуса, прямо или косвенно через предка, или создание невизуализуемого владельца фокуса или non-focusable, инициируют автоматический, прямой обход фокуса. В то время как сокрытие любого предка, легкого веса или тяжеловеса, будет всегда косвенно скрывать свои дочерние элементы, только отключая предка в тяжелом весе отключит его дочерние элементы. Таким образом отключение легкого предка владельца фокуса автоматически не инициирует обход фокуса.
Если клиентский код инициирует обход фокуса, и нет никакого другого Компонента, чтобы фокусироваться, то владелец фокуса остается неизменным. Если клиентский код инициирует автоматический обход фокуса, скрывая владельца фокуса, прямо или косвенно, или делая невизуализуемого владельца фокуса или non-focusable, и нет никакого другого Компонента, чтобы фокусироваться, то глобальный владелец фокуса очищается. Если клиентский код инициирует автоматический обход фокуса, отключая владельца фокуса, прямо или косвенно, и нет никакого другого Компонента, чтобы фокусироваться, то владелец фокуса остается неизменным.
focusable Компонент может стать владельцем фокуса ("focusability") и участвует в обходе клавиатурного фокуса ("фокусируют traversability") с FocusTraversalPolicy. Нет никакого разделения этих двух понятий; Компонент должен или быть и focusable и проходимым фокусом, или ни одним. Компонент выражает это состояние через isFocusable () метод. По умолчанию все Компоненты возвращают true от этого метода. Клиентский код может изменить это значение по умолчанию, вызывая Component.setFocusable (булевская переменная).
Чтобы поддерживать окна палитры и ввести методы, клиентский код может препятствовать тому, чтобы Окно стало фокусируемым Окном. Транзитивностью это предотвращает Окно или любого из его потомков от становления владельцем фокуса. 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
Клиентский код может слушать изменения в состоянии фокуса всего контекста, или к изменениям в связанном с фокусом состоянии в Компонентах, через PropertyChangeListeners.
KeyboardFocusManager
поддерживает следующие свойства:
focusOwner
: владелец фокуса focusedWindow
: фокусируемое Окно activeWindow
: активное окно defaultFocusTraversalPolicy
: политика обхода фокуса по умолчанию forwardDefaultFocusTraversalKeys
: Набор значения по умолчанию FORWARD_TRAVERSAL_KEYS
backwardDefaultFocusTraversalKeys
: Набор значения по умолчанию BACKWARD_TRAVERSAL_KEYS
upCycleDefaultFocusTraversalKeys
: Набор значения по умолчанию UP_CYCLE_TRAVERSAL_KEYS
downCycleDefaultFocusTraversalKeys
: Набор значения по умолчанию DOWN_CYCLE_TRAVERSAL_KEYS
currentFocusCycleRoot
: текущий корень цикла фокуса A PropertyChangeListener
установленный на токе KeyboardFocusManager
будет только видеть эти изменения в пределах KeyboardFocusManager
's контекст, даже при том, что владелец фокуса, фокусировал Окно, активное окно, и текущий корень цикла фокуса включает глобальное состояние фокуса, совместно использованное всеми контекстами. Мы полагаем, что это менее навязчиво чем требование, чтобы клиентский код передал проверку защиты прежде, чем установить a PropertyChangeListener
.
Компонент поддерживает следующие связанные с фокусом свойства:
focusable
: focusability Компонента focusTraversalKeysEnabled
: ключи обхода фокуса Компонента, включенные состояние forwardFocusTraversalKeys
: Набор Компонента FORWARD_TRAVERSAL_KEYS
backwardFocusTraversalKeys
: Набор Компонента BACKWARD_TRAVERSAL_KEYS
upCycleFocusTraversalKeys
: Набор Компонента UP_CYCLE_TRAVERSAL_KEYS
В дополнение к свойствам Component Контейнер поддерживает следующие связанные с фокусом свойства:
downCycleFocusTraversalKeys
: Набор Контейнера DOWN_CYCLE_TRAVERSAL_KEYS
focusTraversalPolicy
: политика обхода фокуса Контейнера focusCycleRoot
: корневое циклом фокусом состояние Контейнера В дополнение к свойствам Container Окно поддерживает следующее связанное с фокусом свойство:
focusableWindow
: focusable Статус окна Окна Также отметьте это a PropertyChangeListener
установленный на Окне никогда не будет видеть a PropertyChangeEvent
для focusCycleRoot
свойство. Окно всегда является корнем цикла фокуса; это свойство не может измениться.
KeyboardFocusManager
также поддерживает VetoableChangeListener
s для следующих свойств:
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
возможно, не содержит блокировок, уведомляя PropertyChangeListener
s изменения состояния. Это требование ослабляется для VetoableChangeListeners
, как бы то ни было. Поэтому, клиент-definied VetoableChangeListener
s должен избежать получать дополнительные блокировки внутри vetoableChange(PropertyChangeEvent)
поскольку это может привести к мертвой блокировке. Если изменение фокуса или активации будет отклонено, то KeyboardFocusManager будет инициировать восстановление отклонения следующим образом:
KeyboardFocusManager
очистит глобального владельца фокуса. KeyboardFocusManager
очистит глобального владельца фокуса. VetoableChangeListener
s должен делать все возможное избежать накладывать вето на изменения фокуса, инициируемые в результате восстановления отклонения вето. Отказ ожидать эту ситуацию мог привести к бесконечному циклу изменений фокуса, на которые накладывают вето, и попыток восстановления.
На некоторых собственных системах управления окнами Z-порядок Окна может влиять на свой фокусируемый, или активные (если применимый) утверждают. На Microsoft Windows самым верхним Окном является естественно фокусируемое Окно также. Однако, на Солярисе, много менеджеров окон используют модель точки к фокусу, которая игнорирует Z-порядок в определении фокусируемого Окна. Фокусируясь или активируя Windows, AWT придерживается требований UI собственной платформы. Поэтому, поведение фокуса методов Z-order-related, таких как:
Window.toFront()
Window.toBack()
Window.show()
Window.hide()
Window.setVisible(boolean)
Window.dispose()
Frame.setState(int)
Window.toFront()
:Window.toBack()
:Window.show()/Window.setVisible(true)/Frame.setState(NORMAL)
:Window.hide()/Window.setVisible(false)/Window.dispose()/ Frame.setState(ICONIFIED)
:
KeyboardFocusManager
s являются сменными на уровне контекста браузера. Клиентский код может разделить на подклассы 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
диспетчеризирование следующих событий:
KeyEvent
s FocusEvent
s WindowEvent.WINDOW_GAINED_FOCUS
WindowEvent.WINDOW_LOST_FOCUS
WindowEvent.WINDOW_ACTIVATED
WindowEvent.WINDOW_DEACTIVATED
KeyboardFocusManager
со всеми вышеупомянутыми событиями кроме WINDOW_ACTIVATED
и WINDOW_DEACTIVATED
. KeyboardFocusManager
должен синтезировать WINDOW_ACTIVATED
и WINDOW_DEACTIVATED
события, когда соответствующий и предназначаются для них соответственно. KeyboardFocusManager
возможно, должен перенастроить события, обеспеченные равноправным уровнем для его собственного понятия владельца фокуса или фокусируемого Окна:
FOCUS_LOST
событие должно быть перенастроено владельцу фокуса. Снова, это необходимо, потому что равноправный уровень не сознает легкие Компоненты. WINDOW_LOST_FOCUS
событие должно быть перенастроено к фокусируемому Окну. Реализация класса Окна может заставить собственное фокусируемое Окно отличаться от Java фокусируемое Окно. 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
попытки установить глобального владельца фокуса в non-focusable Компонент. KeyboardFocusManager
попытки установить глобальную переменную фокусируемое Окно в non-focusable Окно. VetoableChangeListener
. Определенные клиентом реализации KeyboardFocusManager
может скорректировать набор передач фокуса, которые отклоняются, переопределяя средство доступа и мутаторные методы для глобального состояния фокуса.
Если запрос, чтобы изменить глобальное состояние фокуса отклоняется, KeyboardFocusManager
должен отбросить событие, которое запрашивало запрос на изменение фокуса. Компонент, к которому было предназначено событие, не должен получить событие.
KeyboardFocusManager
как также ожидают, будет инициировать восстановление отклонения как обрисовано в общих чертах в Фокусе и VetoableChangeListener.
Наконец, KeyboardFocusManager должен обработать следующий набор особых случаев:
WINDOW_GAINED_FOCUS
событие, KeyboardFocusManager
должен установить фокус в соответствующий дочерний Компонент Окна. Если дочерний Компонент Окна, ранее требуемый фокус, но изменение фокуса был отклонен, потому что платформа не поддерживает запросы на изменение фокуса перекрестного окна, то фокусируется, должен быть установлен в тот дочерний Компонент. Иначе, если Окно никогда не фокусировалось, фокус должен быть установлен в начальный Компонент Окна фокусироваться. Если бы Окно ранее фокусировалось, то фокус должен быть установлен в нового владельца фокуса Окна. KeyboardFocusManager
должен гарантировать, что противоположный Компонент или Окно столь же точны как собственные разрешения на платформу работы с окнами. Например, KeyboardFocusManager
возможно, должен перенастроить противоположный Компонент легкому дочернему элементу тяжеловеса, первоначально определенного равноправным уровнем. null
, это приемлемо для KeyboardFocusManager
распространить это значение. null
указывает, что это чрезвычайно, вероятно, что никакой другой Компонент или Окно не были включены в изменение активации или фокус. Из-за ограничений платформы это вычисление может подвергнуться эвристике и могло быть неправильным. Однако, эта эвристика будет самым лучшим предположением, которое мог высказать равноправный уровень. Межплатформенные изменения:
DefaultFocusTraversalPolicy
поскольку все Контейнеры AWT сохранят порядок обхода предыдущих выпусков. Window.toFront()
и Window.toBack()
теперь не выполните работу, если Окно не видимо. Ранее, поведение было зависимо от платформы. Component
s больше не будет видеть KeyEvent
s, что карта, чтобы фокусировать операции обхода, и Component.handleEvent()
больше не будет вызван для таких событий. Ранее, Компоненты AWT видели эти события и имели возможность использовать их перед AWT инициируемый обход фокуса. Код, который требует этой функциональности, должен вместо этого отключить обход фокуса, включает Component
s и дескриптор фокусируют обход непосредственно. Поочередно, код может использовать AWTEventListener
или KeyEventDispatcher
предварительно слушать все KeyEvent
s. Изменяется определенный для Microsoft Windows:
Window.toBack()
изменяет фокусируемое Окно на самое верхнее Окно после изменения Z-порядка. requestFocus()
теперь позволяет запросы на изменение фокуса перекрестного окна во всех случаях. Ранее, запросы предоставили для тяжеловесов, но отрицались для легких весов.