2015-10-21 2 views
0

Я пытаюсь передать имя метода в прослушиватель действий так, чтобы он мог вызвать этот метод без инструкций 50 if. Я знаю, что в C++ есть указатели на функции, но это не что-то в java. Есть ли способ в Java, чтобы иметь что-то вдоль линийJava JButton pass method call to actionlistener

actionPerfomed(ActionEvent e){ 
    String command = e.getSource().getActionCommand() 
    //use command to look up a method on the implementing class 
    //and call it without an if 

Все методы, которые должны называться не имеют возвращения и не имеют никакого значения, которое должно быть передано им, что они могут получить всю информацию они нуждаются в кадре, которому это принадлежит. Я думаю, что отражение - это правильный вариант, но мой опыт работы с ним ограничен в Java, и я никогда не читал ничего приятного в этом.

Это для идеи работы с каркасом, так что ActionListener может быть выведен из проекта и повторно использован с незначительной модификацией. Я работаю над рамочной работой, которую кто-то другой разработал в моей работе, которая делает это на C# и много чего, как когда-либо был этот парень, когда писал. Поэтому я пытаюсь создать реализацию Java, потому что у C# есть свои ограничения (Windows).

+0

Вид, я бы очень рекомендую это, вероятно, не .. Вы могли бы взгляните на [Reflection API] (https://docs.oracle.com/javase/tutorial/reflect/), или вы можете использовать «Map», который содержит общую реализацию интерфейса, с требуемым методом, который основан на на вашем 'Action' или' actionCommand', смог бы посмотреть, какой экземпляр он должен выполнить, что было бы лучше, чем при использовании рефлекса. – MadProgrammer

+0

@MadProgrammer. Звучит гораздо веселее, чем отражение, но я даже не коснулся карт до. Так вы говорите, чтобы использовать setActionMap на кнопке или дать классу ActionListener карту и использовать строку из команды действий в качестве ключей для поиска метода? – nonprofitgibi

+0

Как правило, у вас будет поле «Карта» в качестве поля экземпляра, ключ которого будет сопоставляться с свойством 'actionCommand'' JButton', поэтому при выполнении вы просматриваете команду и выполняете ее метод – MadProgrammer

ответ

2

Есть несколько способов, вы могли бы это сделать, один может быть, чтобы разработать общий интерфейс, который вся ваша «команде» должен были бы осуществить, он будет иметь один метод, который может выполнить ваш ActionListener.

Например ...

public interface Command { 
    public void execute(); 
} 

Вы бы тогда в вашем UI в Map который будет сопоставить actionCommand сек экземплярам Command s

public class ... extends ... { 
    private Map<String, Command> commands = new HashMap<>(25); 
    //... 

Теперь вы можете иметь хороший " add ", который позволит вам динамически добавлять команды, создавая новую JButton для каждой новой команды или просто настраивая ее самостоятельно в соответствии с вашими потребностями

Затем в ActionListener, вы бы просто получить actionCommand недвижимость, посмотреть вверх Command в Map и execute его, если он действует

@Override 
public void actionPerformed(ActionEvent e) { 
    Command cmd = commands.get(e.getActionCommand()); 
    if (cmd != null) { 
     cmd.execute(); 
    } 
} 

Например ...

package javaapplication659; 

import java.awt.EventQueue; 
import java.awt.GridBagConstraints; 
import java.awt.GridBagLayout; 
import java.awt.Insets; 
import java.awt.event.ActionEvent; 
import java.awt.event.ActionListener; 
import java.util.HashMap; 
import java.util.Map; 
import javax.swing.JButton; 
import javax.swing.JFrame; 
import javax.swing.JPanel; 
import javax.swing.UIManager; 
import javax.swing.UnsupportedLookAndFeelException; 

public class TestCommand { 

    public static void main(String[] args) { 
     new TestCommand(); 
    } 

    public TestCommand() { 
     EventQueue.invokeLater(new Runnable() { 
      @Override 
      public void run() { 
       try { 
        UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName()); 
       } catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) { 
        ex.printStackTrace(); 
       } 

       JFrame frame = new JFrame("Testing"); 
       frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); 
       frame.add(new TestPane()); 
       frame.pack(); 
       frame.setLocationRelativeTo(null); 
       frame.setVisible(true); 
      } 
     }); 
    } 

    public class TestPane extends JPanel { 

     private Map<String, Command> commands = new HashMap<>(25); 
     private ActionListener actionListener; 
     private GridBagConstraints gbc; 

     public TestPane() { 
      setLayout(new GridBagLayout()); 
      gbc = new GridBagConstraints(); 
      gbc.gridwidth = GridBagConstraints.REMAINDER; 
      gbc.fill = GridBagConstraints.HORIZONTAL; 
      gbc.insets = new Insets(1, 1, 1, 1); 
      actionListener = new ActionHandler(); 
      add("Take over the world", new Command() { 
       @Override 
       public void execute() { 
        System.out.println("Take over the world"); 
       } 
      }); 
      add("Quwell up rising", new Command() { 
       @Override 
       public void execute() { 
        System.out.println("Bring the boot down"); 
       } 
      }); 
      add("Buy milk", new Command() { 
       @Override 
       public void execute() { 
        System.out.println("Buy milk"); 
       } 
      }); 
     } 

     public void add(String text, Command cmd) { 
      JButton btn = new JButton(text); 
      btn.addActionListener(actionListener); 
      commands.put(text, cmd); 
      add(btn, gbc); 
     } 

     public class ActionHandler implements ActionListener { 

    @Override 
    public void actionPerformed(ActionEvent e) { 
     Command cmd = commands.get(e.getActionCommand()); 
     if (cmd != null) { 
      cmd.execute(); 
     } 
    } 

     } 

    } 

    public interface Command { 
     public void execute(); 
    } 
} 

Теперь, это довольно простой пример, и может быть гораздо более сложным, в зависимости от ваших потребностей, но она демонстрирует основную идею

+0

Это это очень хорошая реализация и выглядит лучше, чем отражение. Спасибо. – nonprofitgibi

0

Это далеко от идеального решения, но, хотя я мог бы просто сказать, что здесь ...

JButtonSpecial мой класс, распространяется JButton. JButtonSpecial будет содержать метод, который вы хотите передать в ActionListener. Затем вы можете сделать что-то подобное,

button=new JButtonSpecial("Click Here"); 
button.addActionListener(new ActionListener(){ 
    public void actionPerformed(ActionEvent e) { 
     JButtonSpecial tmpButton = (JButtonSpecial)e.getSource(); 
     tmpButton.yourCustomMethod();//this method will be defined in JButtonSpecial 
    } 
}); 

Я согласен вы хотите жёстко имя методы там, но вы можете изменить реализацию метода от объекта к объекту ...

+0

Я думаю, что я вижу, что вы пытаются сказать, что вы уходите из своего кода 'button = new JButtonSpecial() {specialMethod() {/ * method stuff * /} 'Мне нравится эта идея, учитывая, что кто-то, кто ее реализует, мог делать то, что когда-либо захотел после этого, но кажется немного уродливый в реализации, и это не учитывает textItems textFields и многие другие вещи, которые могут иметь actionListiner – nonprofitgibi

+0

Нет, если вы не создаете экстренный прослушиватель, специфичный для всех тех типов, которые вы используете ... Я согласен, что это немного уродливо –

0

Java делает нет указателей на функции, так что вы должны сделать что-то вроде этого:

private JButton button = new JButton("Click me!"); 
public YourClass() 
{ 
    ... 
    button.setActionCommand("foo"); 
    button.addActionListener(this); 
    ... 
} 
public void actionPerformed(ActionEvent e) 
{ 
    String command = e.getActionCommand(); 
    if(command.equals("foo")) 
     foo(); 
    else if(...) 
} 

также как sidenote- e.getSource().getActionCommand() даст вам синтаксическую ошибку. getActionCommand() является методом ActionEvent и getSource() возвращает объект таким образом вы могли бы сделать e.getActionCommand()