Причина, по которой компонент ComponentListener не работает, заключается в том, что он сообщает об изменениях в видимом свойстве - и это верно по умолчанию, даже не будучи частью иерархии компонентов.
Чтобы получать достоверные уведомления, используйте HierarchyListener
Edit (размышления об эволюции моих знаний по этому вопросу / ответам, не уверен, что сетевой этикет говорит о том, как это делать... просто наведите меня, если это неправильный путь: -)
Во-первых: вопрос, заданный в теме, не обязательно связан с реальной проблемой (как прокомментировал Боро ниже - любой способ ссылки накомментарий?): нет необходимости сохранять какой-то локальный флаг, чтобы решить, безопасно ли отправлять getLocationOnScreen компоненту, просто спросите сам компонент.Изучите пункт 1 для себя :-)
Второе: заданный вопрос довольно интересный.Пять экспертов (в том числе и я самопровозглашенный), пять разных ответов.Что вызвало немного копания с моей стороны.
Моя гипотеза: ComponentEvents не полезны для уведомления о (первом) показе.Я знал, что componentShown бесполезен, потому что он является своего рода уведомлением propertyChange о видимом свойстве компонента (которое редко изменяется).Озадаченный предполагаемой полезностью перемещения / изменения размера, однако.
Создание варианта использования: полностью подготовить кадр в примере и сохранить его готовым для последующего показа, типичный подход для улучшения воспринимается спектакль.Мой прогноз - основанный на моей гипотезе: измененный размер / перемещенный уволен во время подготовки, ничего во время шоу (примечание: isShowing - это то, что мы ищем, то есть последнее).Фрагмент, добавляемый в примере OP:
final JFrame f = new JFrame();
f.setContentPane(contentPane);
f.setSize(800, 600);
// f.pack();
JFrame controller = new JFrame("opener");
controller.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
Action open = new AbstractAction("open/hide second") {
@Override
public void actionPerformed(ActionEvent e) {
f.setVisible(!f.isVisible());
}
};
controller.add(new JButton(open));
controller.pack();
controller.setVisible(true);
Разочарование: нет уведомлений во время подготовки, уведомлений во время показа, просто по мере необходимости, моя гипотеза казалась неверной ;-) Последний шанс: поменять местами setSizeза пачку ... и вуаля, уведомление во время подготовки, без уведомления во время шоу, снова меня радует.Игра немного больше: похоже, что ComponentEvents запускаются, если компонент отображается, что может или не может быть полезным в некоторых контекстах, но не в том случае, если показывается состояние, к которому мы стремимся.
Новые имперские правила (черновик):
Не используйте ComponentListener для уведомления о «показе».Это осталось от возраста AWT.
Используйте AncestorListener.Это похоже на замену Swing, слегка ошибочное уведомление о «добавленном», что фактически означает «показывающий»
Использовать HierarchyListener, только если действительно заинтересованы в детальных изменениях состояния