У меня есть приложение, где, если действие пользователя занимает определенное время, отображается диалоговое окно, в котором интерфейс обрабатывает действие. Обычно, когда действие выполняется, диалог закрывается, и пользователь может продолжать делать то, что он делал раньше. Кажется, что это работает почти всегда, но время от времени фокус перемещается из компонента, который был сфокусирован на компонент, который находится в 2 местах после него в цепочке фокуса.Неверное поле сфокусировано после закрытия диалога
Я не могу создать небольшую примерную программу, чтобы показать, что именно происходит, но я смог отладить проблему до такой степени, что я надеюсь, что кто-то может мне помочь.
Что, кажется, происходит это:
- sun.awt.TimedWindowEvent [WINDOW_GAINED_FOCUS, {главное окно} ...] событие обрабатывается в диалоге и передается на DefaultKeyboardFocusManager (DKFM), который попытается восстановить фокус в главное окно.
- DKFM говорит MostRecentFocusOwner сосредоточить себя
- Компонент регистрирует себя как MostRecentFocusOwner и пытается на самом деле сосредоточиться на себя, вызвав peer.requestFocus.
- * В WComponentPeer, кадр сфокусирован, но по какой-то причине он возвращает ложь
- компонент видит не фокусировалось, так что возвращает ложь, а
- DKFM видит, что компонент не был сосредоточены так он пытается сосредоточиться следующий компонент
- Шаг 3-5
- Еще одно событие вызывает фокус, шаг 1-7 запуска снова, но потому, что шаг 3 регистров нового компонента в MostRecentFocusOwner цикл переходит компонента из 6 и следующий оттуда
- Еще одно событие фокусировки запускает логику с шага 1, но теперь шаг 4 возвращает true. Отобразится главное окно, и теперь будет сфокусирован неправильный компонент.
Для 4 *: Дело в том, что, как представляется, отличается в тех ситуациях, где он работает и где она не в том, что проверяет WComponentPeer после запроса фокусировки для ParentWindow где в правильных ситуациях parentWindow.isFocused() истинно, и в неудачных ситуациях parentWindow.isFocused() вернет false. Запись, отображаемая при включении регистрации фокуса, - «rejectFocusRequestHelper [...] Ожидание асинхронной обработки запроса».
Это, по-видимому, указывает на то, что WComponentPeer знает о возможности обработки асинхронно запросов фокусировки, но DKFM этого не делает.
Соответствующий StackTrace выглядит следующим образом:
KeyboardFocusManager.setMostRecentFocusOwner(Window, Component) line: 1814
KeyboardFocusManager.setMostRecentFocusOwner(Component) line: 1801
TheComponent(Component).requestFocusHelper(boolean, boolean, CausedFocusEvent$Cause) line: 7618 (3)
TheComponent(Component).requestFocusInWindow(CausedFocusEvent$Cause) line: 7533
DefaultKeyboardFocusManager.doRestoreFocus(Component, Component, boolean) line: 172 (6)
DefaultKeyboardFocusManager.restoreFocus(Window, Component, boolean) line: 151 (2)
DefaultKeyboardFocusManager.restoreFocus(WindowEvent) line: 134
DefaultKeyboardFocusManager.dispatchEvent(AWTEvent) line: 302
ProgressDialog(Component).dispatchEventImpl(AWTEvent) line: 4731 (1)
Так что мой вопрос, я смотрю на ошибку Java здесь?
Кроме того, в документации упоминается, что вы не должны предполагать, что изменение фокуса выполняется синхронно, но оно не объясняет, когда оно синхронно, и когда это не так, что заставляет систему фокусировки в Java обрабатывать определенные запросы фокуса асинхронно и другие синхронно?
Редактировать: Это может быть событие заказа событий. Глядя на focusedWindow в KeyboardFocusManager в правильной ситуации это выглядит следующим образом:
- Основной каркас -> нулевой
- Null -> Диалог Диалог
- изменения фокуса (я ожидаю диалога)
- -> нулевой
- нуль -> Главный кадр
- Фокус изменение (в lastFocussedComponent
В неисправной ситуации это так:
- Основного каркас -> нулевого
- 4x Фокусное изменение (к следующему фокусируемой компоненте на основной раме)
- нуля -> Главного кадра
Кажется, что диалог удален до того, как он будет показан. Событие, которое очищает основной кадр в качестве активного окна, в обоих случаях имеет WINDOW_FOCUS_LOST TimedWindowEvent с диалогом, противоположным.