Когда во время инициализации я могу добавить ComponentListener, чтобы он не запускал componentResized?

Ответ, я думаю, будет после того, как все начальные размеры компонентов будут выполнены, но взгляните на этот SSCCE:

import javax.swing.*;
import java.awt.*;
import java.awt.event.*;

public class Test2 {

  private static void createAndShowGUI2() {

    final JFrame frame = new JFrame("Test2");
    frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

    JButton addSecondListener = new JButton("Click me to add a second listener");
    addSecondListener.addActionListener(new ActionListener() {
      public void actionPerformed(ActionEvent e) {
        frame.addComponentListener(new ComponentAdapter() {
          public void componentResized(ComponentEvent e) {
            System.out.println("Component Listener 2");
          }
        });
      }
    });

    frame.getContentPane().add(addSecondListener);

    frame.setSize(200, 200);
    frame.setVisible(true);

    frame.addComponentListener(new ComponentAdapter() {
      public void componentResized(ComponentEvent e) {
        System.out.println("Component Listener 1");
        //throw new NullPointerException("Just getting traceback...");
      }
    });

  }

  public static void main(String[] args) {
    //Schedule a job for the event-dispatching thread:
    //creating and showing this application's GUI.
    javax.swing.SwingUtilities.invokeLater(new Runnable() {
      public void run() {
        createAndShowGUI2();
      }
    });
  }
}

Несмотря на то, что Component Listener 1 добавляется после изменения размера кадра и его отображения, событие изменения размера вызывается при запуске java Test2; он напечатает Component Listener 1 первым делом.

Первоначально это привело меня к мысли, что добавление прослушивателя компонента всегда будет вызывать событие изменения размера сразу после этого. Однако, это не так. Если вы нажмете кнопку JButton внутри фрейма, будет добавлен слушатель компонента 2, и вы не увидите его печать Component Listener 2 так, как вы, вместо этого он сработает только при изменении размера фрейма.

Что заставляет прослушиватель компонента срабатывать после того, как размер кадра был изменен, прежде чем он даже стал видимым? Я бросил там исключение, чтобы увидеть, что трассировка (в настоящее время закомментирована), чтобы дать мне несколько подсказок:

Exception in thread "AWT-EventQueue-0" java.lang.NullPointerException: Just getting traceback...
    at Test2$2.componentResized(Test2.java:31)
    at java.awt.Component.processComponentEvent(Component.java:5960)
    at java.awt.Component.processEvent(Component.java:5914)
    at java.awt.Container.processEvent(Container.java:2023)
    at java.awt.Window.processEvent(Window.java:1816)
    at java.awt.Component.dispatchEventImpl(Component.java:4501)
    at java.awt.Container.dispatchEventImpl(Container.java:2081)
    at java.awt.Window.dispatchEventImpl(Window.java:2458)
    at java.awt.Component.dispatchEvent(Component.java:4331)
    at java.awt.EventQueue.dispatchEvent(EventQueue.java:599)
    at java.awt.EventDispatchThread.pumpOneEventForFilters(EventDispatchThread.java:269)
    at java.awt.EventDispatchThread.pumpEventsForFilter(EventDispatchThread.java:184)
    at java.awt.EventDispatchThread.pumpEventsForHierarchy(EventDispatchThread.java:174)
    at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:169)
    at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:161)
    at java.awt.EventDispatchThread.run(EventDispatchThread.java:122)

Для моего приложения я хочу добавить ComponentListener после того, как все начальные размеры будут установлены программно без запуска componentResized (пока пользователь фактически не изменит размер фрейма/компонента). Как я могу это сделать?

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


person danglingPointer    schedule 11.09.2015    source источник


Ответы (1)


Вы можете добавить прослушиватель внутрь SwingUtilities.invokeLater(), чтобы перед добавлением прослушивателя сначала изменялся размер фрейма (я не думаю, что это будет считаться обходным решением):

SwingUtilities.invokeLater(new Runnable() {
    public void run() {
        frame.addComponentListener(new ComponentAdapter() {
            public void componentResized(ComponentEvent e) {
                System.out.println("Component Listener 1");
            }
        });
    }
});
person Lukas Rotter    schedule 11.09.2015
comment
(1+) I just want to know what is going on. — процесс создания видимого кадра приводит к тому, что в конец EDT добавляется некоторая обработка, поэтому ваш ComponentListener добавляется до того, как сгенерировано событие comonentResized. Этот подход — один из способов убедиться, что событие генерируется первым. - person camickr; 12.09.2015
comment
Так что это медленный ответ, и извините за это, но запуск графического интерфейса уже был внутри вызова позже. Я не был уверен, видели ли вы это, но я попытался изменить свой код/добавить ваш в нескольких местах, например, где находится текущий прослушиватель или после другого вызова позже в основном, однако я все еще вижу печать компонента 1 прослушивателя во время запуска. Я также пытался запустить графический интерфейс не внутри вызова позже, но я почти уверен, что это не очень хорошая идея? - person danglingPointer; 22.09.2015