【问题标题】:How to properly add an ActionListeren to a custom JComponent如何正确地将 ActionListeren 添加到自定义 JComponent
【发布时间】:2013-07-16 09:28:17
【问题描述】:

我经常实现一些面板,它们提供控件等常用功能。为此,我希望能够添加侦听器,以便调用者可以附加到控件并获取有关更改的通知。

到目前为止,我只是使用我自己的List 来保存监听器,当我想触发一个操作时,我会遍历列表并调用监听器。从外面看,这基本上看起来像任何其他 Swing 控件,但我想知道这是否真的是应该使用的方法。

我特别想知道Swing 本身是否也在循环中调用侦听器,或者是否有某种队列可以放置操作,以便Swing 决定何时交付此类操作。

当我对此进行调查时,我发现了这段代码:

protected void fireActionPerformed(ActionEvent event)
{
    Object[] listeners = listenerList.getListenerList();
    ActionEvent e = null;

    // Process the listeners last to first, notifying
    // those that are interested in this event
    for (int i = listeners.length-2; i>=0; i-=2)
    {
        if(listeners[i] instanceof ActionListener)
        {
            // Lazily create the event:
            if (e == null)
            {
                String actionCommand = event.getActionCommand();

                e = new ActionEvent(this,
                        ActionEvent.ACTION_PERFORMED,
                        actionCommand,
                        event.getWhen(),
                        event.getModifiers());
                e.setSource(event.getSource());
            }
            ((ActionListener)listeners[i+1]).actionPerformed(e);
        }
    }
}

直接访问JComponent中的成员listenerList,感觉有点奇怪。但是到目前为止,我并没有真正找到更好的方法。此外,在为此添加新侦听器时,我现在如下所示执行此操作,但我不确定这是否真的是合适的方式:

public void addQueryListener(ActionListener oListener)
{
    listenerList.add(ActionListener.class, oListener);
}

public void removeQueryListener(ActionListener oListener)
{
    listenerList.remove(ActionListener.class, oListener);
}

所以我想知道,访问listenerList 成员是否是添加和删除侦听器的正确方法,以便它们的行为与任何其他标准控件一样?还是有一些best practice 应该怎么做,到目前为止我还没有找到?

【问题讨论】:

    标签: java swing listener actionlistener jcomponent


    【解决方案1】:

    记住 Swings 对创建 gui 的限制。访问没有任何危害 ** listenerlist ** 这样。可能这不是最好的方法。 Swing 是单线程的,不是线程安全的。

    http://codeidol.com/java/java-concurrency/GUI-Applications/Why-are-GUIs-Single-threaded/

    需要在 EDT(事件调度线程)上调用 AddListener 和 RemoveListener 见见http://en.wikipedia.org/wiki/Event_dispatching_thread

    另见 Listenere 的迭代,即当您调用 getActionListeners 时

    它会创建一个 ListenersList 的副本并返回给你

    以下来自 EventListenerList 的代码

    public <T extends EventListener> T[] getListeners(Class<T> t) {
    Object[] lList = listenerList; 
    int n = getListenerCount(lList, t); 
        T[] result = (T[])Array.newInstance(t, n); 
    int j = 0; 
    for (int i = lList.length-2; i>=0; i-=2) {
        if (lList[i] == t) {
        result[j++] = (T)lList[i+1];
        }
    }
    return result;   
    }
    

    【讨论】:

      【解决方案2】:

      EventListenerList 文档中有一个很好的示例,这个Converter 示例在ConverterRangeModel 中使用了自己的listenerList

      【讨论】:

      • 我想这是我从哪里获得触发事件的样本,因为我不记得我在哪里找到它。好吧,似乎访问 listenerList 是要走的路,尽管直接访问成员感觉有点奇怪。 :)
      • 我已经看到它在JComponent 子类中使用过,也像在JFreeChart 中一样单独使用。
      猜你喜欢
      • 2015-02-04
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-11-06
      • 1970-01-01
      • 2021-12-20
      • 2022-12-07
      相关资源
      最近更新 更多