Как программно отправить ActionEvent в JButton?

Как программно отправить ActionEvent (например, нажатие кнопки /ACTION _PERFORMED) на JButton?

Я знаю:

button.doClick(0);

и

button.getModel().setArmed(true);
button.getModel().setPressed(true);
button.getModel().setPressed(false);
button.getModel().setArmed(false);

Но не возможно ли прямо отправить его ActionEvent?

EDIT: Это не производственный код, это всего лишь небольшой личный эксперимент.

Ответ 1

Вы можете получить кнопку ActionListener s, а затем вызвать метод actionPerformed напрямую.

ActionEvent event;
long when;

when  = System.currentTimeMillis();
event = new ActionEvent(button, ActionEvent.ACTION_PERFORMED, "Anything", when, 0);

for (ActionListener listener : button.getActionListeners()) {
    listener.actionPerformed(event);
}

Ответ 2

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

public void actionPerformed(ActionEvent ae) {
    //SomeLogic
}

//...

public void someOtherPlace() {
    //I want to invoke SomeLogic from here though!
}

Но на самом деле решение состоит в том, чтобы извлечь эту логику из ActionListener и вызвать ее как из ActionListener, так и для второго местоположения:

public void someLogic() {
    //SomeLogic
}

public void actionPerformed(ActionEvent ae) {
    someLogic();
}

//...

public void someOtherPlace() {
    someLogic();
}

Ответ 3

Только если вы наследуете и выставляете fireActionPerformed метод, который защищен:

class MockButton extends JButton { 
   // bunch of constructors here 
   @Override 
   public void fireActionPerformed( ActionEvent e ) { 
       super.fireActionPerformed( e );
   }
}

Тогда вы сможете, но, конечно, вам нужно использовать ссылку, например:

MockButton b = .... 

b.fireActionPerformed( new Action... etc. etc

Зачем вам это нужно? Я не знаю, но я предлагаю вам следовать Отметить совет

Ответ 4

Если вы не хотите вызывать doClick() на кнопке, вы можете просто вызвать код, вызываемый действием кнопки. Возможно, вы хотите, чтобы любой класс, содержащий метод actionPerformed, вызывал общедоступный метод, который могут вызвать другие классы, и просто называть этот метод.

Ответ 5

Практическая проблема была решена, кажется (см. Mark Peters и ответы jjnguy's). И метод fireActionPerformed также уже упоминался (см. ответ OscarRyz), чтобы избежать потенциальных проблем concurrency.

Что я хотел добавить, так это то, что вы можете вызывать все частные и защищенные методы (включая fireActionPerformed), без необходимости подкласса любых классов, используя отражение. Во-первых, вы получаете объект Method для отражения частного или защищенного метода с помощью method = clazz.getDeclaredMethod() (clazz должен быть Class объектом класса, который объявляет метод, а не один из его подклассов (т.е. AbstractButton.class для метода fireActionPerformed, а не JButton.class)). Затем вы вызываете method.setAccessible(true) для подавления IllegalAccessException, который в противном случае возникает при попытке доступа к закрытым или защищенным методам/полям. Наконец, вы вызываете method.invoke().

Я не достаточно знаю об отражении, чтобы иметь возможность перечислять недостатки использования отражения. Они существуют, однако, в соответствии с API-интерфейсом Reflection (см. Раздел "Недостатки отражения" ).

Вот какой рабочий код:

// ButtonFireAction.java
import javax.swing.AbstractButton;
import javax.swing.JButton;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.lang.reflect.Method;

public class ButtonFireAction
{
    public static void main(String[] args) throws ReflectiveOperationException
    {
      JButton button = new JButton("action command");
      Class<AbstractButton> abstractClass = AbstractButton.class;
      Method fireMethod;

      // signature: public ActionEvent(Object source, int id, String command)
      ActionEvent myActionEvent = new ActionEvent(button,
                                                  ActionEvent.ACTION_PERFORMED,
                                                  button.getActionCommand());
      button.addActionListener(new ActionListener() {
        public void actionPerformed(ActionEvent e)
        {
          System.out.println(e.getActionCommand());
        }
      });

      // get the Method object of protected method fireActionPerformed
      fireMethod = abstractClass.getDeclaredMethod("fireActionPerformed",
                                                   ActionEvent.class);
      // set accessible, so that no IllegalAccessException is thrown when
      // calling invoke()
      fireMethod.setAccessible(true);

      // signature: invoke(Object obj, Object... args)
      fireMethod.invoke(button,myActionEvent);
    }
}