处置SWT事件侦听器

时间:2019-06-21 07:40:16

标签: java swt listener dispose lifecycle

我正在SWT桌面应用程序上工作,在该应用程序中,我们为各种小部件使用了很多侦听器。目前,我正在尝试管理这些侦听器的生命周期,当我找到解决方案时,我很好奇自己是否错过了某些事情,或者是否可以做得更好。

情况如下:

执行数据绑定时,根据属性信息,将创建多个SWTEventListener(验证,修改,焦点...)。默认情况下,它们只是添加到窗口小部件的事件表中,但是因为删除侦听器需要一个特定的实例,所以:

widget.removeListener(SWT.Verify, formatVerifyListener);

我们决定将所有侦听器保存在一个多图(Map<Widget, List<AbstractDataBindingListener>)中,当我们处理此特定上下文时,我们尝试删除所述侦听器:

for(Entry<Widget, List<AbstractDataBindingListener>> entry : boundWidgets.entrySet()) {
    for (AbstractDataBindingListener listener : entry.getValue()) {
        entry.getKey().removeListener(listener.getSwtEvent, listener);
    }
    entry.getValue().clear();
}
boundWidgets.clear(); // rendundant?
boundWidgets = new HashMap<>();

这不起作用。抽象类被声明为侦听器,因此widget.removeListener(...)会接受它,并且确实接受了,但是所有这些SWTEventListeners都是Typed侦听器,也就是它们确实包含了确切的侦听器,但它们在EventTable.unhook中的if会失败。

public void unhook (int eventType, Listener listener) {
    if (types == null) return;
    for (int i=0; i<types.length; i++) {
        if (types [i] == eventType && listeners [i] == listener) {
            remove (i);
            return;
        }
    }
}

因为:

listeners [i] == listener
// listeners [i] -> the listener I want removed
// listener -> typed listener, different from listener [i]
// but it wraps the correct listener

如果if失败,则不会删除侦听器。

但是Widget确实有一种可以正常工作的方法

protected void removeListener (int eventType, SWTEventListener listener) {
    checkWidget();
    if (listener == null) error (SWT.ERROR_NULL_ARGUMENT);
    if (eventTable == null) return;
    eventTable.unhook (eventType, listener);
}

// EventTable unhook
public void unhook (int eventType, SWTEventListener listener) {
    if (types == null) return;
    for (int i=0; i<types.length; i++) {
        if (types [i] == eventType) {
            if (listeners [i] instanceof TypedListener) {
                TypedListener typedListener = (TypedListener) listeners [i];
                if (typedListener.getEventListener () == listener) {
                    remove (i);
                    return;
                }
            }
        }
    }
}

但是,我当然无法访问它。访问它的唯一方法是使用.removeVerifyListener.removeFocusListener.removeModifyListener

最终的解决方案是创建一个抽象的dispose方法,并强制每个侦听器都拥有它们所附加的窗口小部件的副本(希望没有人将它们附加到其他窗口小部件,并且不能正确更新内容),以便他们可以将自己删除:

public class FloatFormatterVerifyListener extends AbstractDataBindingListener implements VerifyListener {

    // ...

    /** {@inheritDoc} */
    @Override
    public void dispose() {
        for (Widget widget : boundWidgets)
            if (widget != null && !widget.isDisposed()) {
                widget.removeVerifyListener(this);
            }
    }
}

虽然这可行,但恕我直言有点儿优雅……它不是万无一失的。仍然可以将widget.addVeifyListener(floatFormatterVerifyListener)应用于另一个窗口小部件,并且处理对该窗口小部件不起作用。添加它的人还应该保存侦听器的实例并手动处理它。

但是大多数情况与上述情况相似,我们在列表中有许多不同类型的侦听器,每个侦听器都需要自己的.remove[Type]Listener


那有什么解决方案?我们是否应该始终将实际的侦听器(实现VerifyListener)隐藏为私有内部类,并管理由负责跟踪小部件并能够正确处理自身的父类添加它们,或者还有另一种方法不需要反射或instanceof?

0 个答案:

没有答案