How do I programmatically send ActionEvent to JButton?

前端 未结 5 1835
太阳男子
太阳男子 2020-12-20 11:56

How do I programmatically send an ActionEvent (eg button pressed/ACTION_PERFORMED) to a JButton?

I know of:

button.doClick(         


        
相关标签:
5条回答
  • 2020-12-20 12:18

    You can get a button's ActionListeners, and then call the actionPerformed method directly.

    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);
    }
    
    0 讨论(0)
  • 2020-12-20 12:18

    The practical problem was solved, it seems (see Mark Peters' and jjnguy's answers). And the fireActionPerformed method was also already mentioned (see OscarRyz' answer), for avoiding potential concurrency problems.

    What I wanted to add was that you can call all private and protected methods (including fireActionPerformed), without the need to subclass any classes, using reflection. First, you get the reflection Method object of a private or protected method with method = clazz.getDeclaredMethod() (clazz needs to be the Class object of th class that declares the method, not one of its subclasses (i.e. AbstractButton.class for the method fireActionPerformed, not JButton.class)). Then, you call method.setAccessible(true) to suppress the IllegalAccessExceptions that will otherwise occur when trying to access private or protected methods/fields. Finally, you call method.invoke().

    I do not know enough about reflection, however, to be able to list the drawbacks of using reflection. They exist, though, according to the Reflection API trail (see section "Drawbacks of Reflection").

    Here some working code:

    // 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);
        }
    }
    
    0 讨论(0)
  • 2020-12-20 12:20

    If you don't want to call doClick() on the button, then you can simply call the code called by the button's action. Perhaps you want to have whatever class that holds the actionPerformed method call a public method that other classes can call, and simply call this method.

    0 讨论(0)
  • 2020-12-20 12:33

    Even if you could, why would you want to? Usually when people want to do something like this, it means they haven't properly separated the concerns of the UI from business logic. Typically they want to invoke some logic that occurs in an ActionListener without needing the action to take place.

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

    But really the solution is to extract that logic from the ActionListener and invoke it from both the ActionListener and that second location:

    public void someLogic() {
        //SomeLogic
    }
    
    public void actionPerformed(ActionEvent ae) {
        someLogic();
    }
    
    //...
    
    public void someOtherPlace() {
        someLogic();
    }
    
    0 讨论(0)
  • 2020-12-20 12:36

    Only if you inherit and expose the fireActionPerformed method, which is protected:

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

    Then you will be able, but of course, you have to use a reference like this:

    MockButton b = .... 
    
    b.fireActionPerformed( new Action... etc. etc
    

    Why would you like to do that? I don't know, but I would suggest you to follow Mark's advice

    0 讨论(0)
提交回复
热议问题