Generi c (JComponent) обработка событий в Java? - PullRequest
0 голосов
/ 27 апреля 2020

Я реализую язык сценариев поверх Java VM. Используя отражение, я могу динамически создавать вспомогательные объекты Java, получать доступ к их полям и вызывать их методы. Однако теперь у меня есть жестко запрограммированная обработка для определенных типов событий c. Например: JScrollBar addAdjustmentListener () с использованием настраиваемого интерфейса, JFrame windowClosing () с использованием интерфейса WindowAdapter, JButton addActionListener с использованием интерфейса ActionListener. На стороне получения события на языке сценариев вызывается анонимная функция с данными события с 0, 1 или 2 параметрами произвольных типов. Мой вопрос: есть ли в (1005 *) (рефлексивный) способ обрабатывать произвольные события? Общая обработка всех событий подкласса JComponent также будет хорошим началом.

1 Ответ

2 голосов
/ 28 апреля 2020

Следующий код может служить вам отправной точкой:

public static void main(String[] args) {
    JFrame f = new JFrame("example");
    listenToAllEvents(f, System.out, "println");
    JButton b = new JButton("click me");
    listenToAllEvents(b, System.out, "println");
    f.getContentPane().add(b, BorderLayout.PAGE_START);
    f.pack();
    f.setDefaultCloseOperation(JFrame.DO_NOTHING_ON_CLOSE);
    f.addWindowListener(
        EventHandler.create(WindowListener.class, f, "dispose", null, "windowClosing"));
    f.setVisible(true);
}
static void listenToAllEvents(Object component, Object listener, String method) {
    BeanInfo bi;
    try {
        bi = Introspector.getBeanInfo(component.getClass());
    } catch (IntrospectionException ex) {
        LOGGER.log(Level.SEVERE, null, ex);
        return;
    }
    for(EventSetDescriptor esd: bi.getEventSetDescriptors()) try {
        esd.getAddListenerMethod().invoke(component,
            EventHandler.create(esd.getListenerType(), listener, method, ""));
    } catch(ReflectiveOperationException ex) {
        LOGGER.log(Level.SEVERE, null, ex);
    }
}

Ключевыми точками являются

  • BeanInfo, возвращаемое Introspector.getBeanInfo(…) позволяет динамически определять, какие события поддерживает компонент, т. Е. Какие методы он объявляет в соответствии с шаблоном источника события.
  • Класс EventHandler позволяет генерировать слушатели, которые вызывать определенный целевой метод, когда происходит событие. Это также позволяет передавать результат вызова метода для события в качестве аргумента целевому методу. Кроме того, как показано в примере windowClosing → dispose, поддерживаются методы без аргументов и указание определенных методов прослушивателя.
  • EventHandler основан на Proxy, который позволяет реализовать произвольные интерфейсы через общий InvocationHandler, который может быть очень полезен для других целей в контексте вашего языка сценариев, если только вы не хотите go путь генерации байт-кода.

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

...