如何自定义ActionEvent的事件源?

时间:2016-04-19 15:50:32

标签: java swing inheritance actionlistener

我正在开发一个自定义组件,并提出了一个问题。这是组件:

public class MyComponent extends JPanel {

    private final JButton jButton;
    private final JLabel jLabel;

    public MyComponent(){
        jButton = new JButton();
        //etc..
    }

    public void addActionListener(ActionListener l){
         //The problem with this is that ActionEvent has source attribute 
         //set to jButton which is not desirable. How can I set it to this?
         jButton.addActionListener(l);
    }

    //other component-specific methods
}

问题是我试图隐藏MyComponent的实施细节。但是以这种方式设置监听器并不好,因为调用者可能会发现source attrubte是jButton。如何设置封闭的MyComponent实例?

2 个答案:

答案 0 :(得分:2)

不是允许客户端传入ActionListener,而是让客户端传入不同的回调,创建自己的侦听器,然后让侦听器调用回调:

public class MyComponent extends JPanel {
    private final JButton jButton;

    public MyComponent(){
        jButton = new JButton();
    }

    public void addActionListener(SomeCallback callback){
        jButton.addActionListener(event -> { //create listener
            callback.execute(); //invoke callback
        });
    }
}

interface SomeCallback {
    void execute();
}

如果您想通过ActionEvent无法访问ActionEvent#getSource()的客户端,请创建一个包装器:

class ActionEventWrapper {
    private ActionEvent event;

    public MyActionEvent(ActionEvent event) {
        this.event = event;
    }

    //expose methods that aren't getSource()
    public String getActionCommand() {
        return event.getActionCommand();
    }
}

只需将此类型添加到回调的方法参数:

interface SomeCallback {
    void execute(ActionEventWrapper event);
}

然后,您可以在触发事件时随时创建新的ActionEventWrapper

    public void addActionListener(SomeCallback callback){
        jButton.addActionListener(event -> {
            callback.execute(new ActionEventWrapper(event));
        });
    }

如果您真的想调整组件侦听器事件的来源,只需创建一个新的ActionEvent,通过构造函数指定您想要的任何来源:

public void addActionListener(ActionListener listener) {
    jButton.addActionListener(event -> {
        listener.actionPerformed(new ActionEvent(..., event.getID(), event.getActionCommand()));
    });
}

您可以在...指定要作为来源的组件。

答案 1 :(得分:1)

以下应该工作。

@SuppressWarnings("all")
public class MyComponent extends JPanel {
    private final JButton jButton = new JButton();
    private final JLabel jLabel = new JLabel();

    public void addActionListener(final ActionListener listener) {
        final MyComponent self = this;

        ActionListener newListener = new ActionListener() {
            public void actionPerformed(ActionEvent e) {
                ActionEvent newEvent = new ActionEvent(e.getSource(), e.getID(), e.getActionCommand()) {
                    @Override
                    public Object getSource() {
                        return self;
                    }
                };
                listener.actionPerformed(newEvent);
            }
        };
        jButton.addActionListener(newListener);
    }
}

使用Lambda表达式(单数)

@SuppressWarnings("all")
public class MyComponent2 extends JPanel {
    private final JButton jButton = new JButton();
    private final JLabel jLabel = new JLabel();

    public void addActionListener(final ActionListener listener) {
        MyComponent2 self = this;

        jButton.addActionListener(e-> {
            ActionEvent newEvent = new ActionEvent(e.getSource(), e.getID(), e.getActionCommand()) {
                @Override
                public Object getSource() {
                    return self;
                }
            };
            listener.actionPerformed(newEvent);
        });
    }
}