简体   繁体   English

如何自定义ActionEvent的事件源?

[英]How to customize event source for ActionEvent?

I'm working on a custom component and came up with a problem. 我正在处理一个自定义组件,并提出了一个问题。 Here is the component: 这是组件:

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
}

The thing is I'm trying to hide MyComponent 's implementation details. 问题是我试图隐藏MyComponent的实现细节。 But setting listener this way is not good since a caller may observe that source attrubte is jButton . 但是以这种方式设置侦听器并不好,因为调用者可能会发现source属性为jButton How can I set to the enclosing MyComponent instance? 如何设置为封闭的MyComponent实例?

Instead of allowing the client to pass in an ActionListener , have the client pass in a different callback, create your own listener, then have your listener invoke the callback: 与其允许客户端传递一个ActionListenerActionListener让客户端传递一个不同的回调,创建自己的侦听器,然后让您的侦听器调用该回调:

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();
}

If you want to pass the client the ActionEvent without the ability to access ActionEvent#getSource() , create a wrapper: 如果要向客户端传递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();
    }
}

Simply add this type to the callback's method parameter: 只需将此类型添加到回调的method参数中:

interface SomeCallback {
    void execute(ActionEventWrapper event);
}

You could then create a new ActionEventWrapper anytime an event is triggered: 然后,您可以在触发事件的任何时候创建一个新的ActionEventWrapper

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

If you really want to adjust the source of the component's listener's events, simply create a new ActionEvent , specifying whichever source you want via the constructor: 如果您确实要调整组件的侦听器事件的源,只需创建一个新的ActionEvent ,即可通过构造函数指定所需的源:

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

The ... is where you specify which component you want to act as the source. ...是您在其中指定要用作源的组件的位置。

Following should work. 以下应该工作。

@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);
    }
}

With Lambda expression (singular) 带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);
        });
    }
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM