Как программно отправить ActionEvent в JButton? - PullRequest
13 голосов
/ 21 января 2011

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

Я знаю:

button.doClick(0);

и

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

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

РЕДАКТИРОВАТЬ: Это не рабочий код, это всего лишь небольшой личный эксперимент.

Ответы [ 5 ]

15 голосов
/ 21 января 2011

Вы можете получить 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);
}
13 голосов
/ 21 января 2011

Даже если бы вы могли, почему вы бы хотели? Обычно, когда люди хотят сделать что-то подобное, это означает, что они не должным образом отделили интересы пользовательского интерфейса от бизнес-логики. Как правило, они хотят вызвать некоторую логику, которая происходит в 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 голосов
/ 21 января 2011

Только если вы наследуете и выставляете метод 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

Зачем тебе это делать? Я не знаю, но я бы посоветовал вам следовать совету Марка

1 голос
/ 21 января 2011

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

0 голосов
/ 24 мая 2014

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

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

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

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

// 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);
    }
}
...