如何添加响应任何首选项更改的 IPreferenceChangeListener?

How can I add an IPreferenceChangeListener that responds to any preference change?

我想添加一个将在 任何 Eclipse 首选项更改时触发的侦听器。

我知道如何使用声明页面的 UI 插件的 Activator 为特定的首选项页面执行此操作。您可以使用从 Activator.start() 方法调用的以下 API:

getPreferenceStore().addPropertyChangeListener(IPropertyChangeListener listener)

但我希望在任何偏好更改时都能通知收听者。我尝试了以下方法,从我的 Activator.start() 方法调用:

import org.eclipse.ui.plugin.AbstractUIPlugin;
import org.osgi.framework.BundleContext;

public class Activator extends AbstractUIPlugin {
...
    public void start(BundleContext context) throws Exception {
        super.start(context);
        plugin = this;
        addMyPreferenceChangeListener();
    }

    private IPreferenceChangeListener fPreferenceChangeListener;
    private void addMyPreferenceChangeListener() {
        fPreferenceChangeListener = new IPreferenceChangeListener() {
            public void preferenceChange(PreferenceChangeEvent event) {
                System.err.println("PreferenceChangeEvent");
            }
        };
        IEclipsePreferences prefs = InstanceScope.INSTANCE.getNode("/");
        prefs.addPreferenceChangeListener(fPreferenceChangeListener);
    }
}

我希望getNode的“/”可以指示偏好的根,但这似乎行不通;当我更改首选项时,println() 不会执行(例如:Window > Preferences > General > Always 运行 in background)。

没有办法让所有节点都收到通知的单个侦听器,您必须为您感兴趣的每个节点添加一个侦听器。

您可以使用 IPreferenceNodeVisitor

找到所有现有节点
IPreferencesService prefsService = Platform.getPreferencesService();

IEclipsePreferences root = prefsService.getRootNode();

root.accept(visitor);

您还必须使用 IEclipsePreferences.addNodeChangeListener 才能获知新节点。

另请注意,您的激活器的 start 方法不会 运行 直到您的插件中的某些其他代码被使用 - 它通常不会 运行 在 Eclipse 启动期间。

感谢 greg-449 的回答。这是我的最终代码供参考。 首选项侦听器是从 Activator 启动方法添加的。请注意,此插件在启动时使用 extension point="org.eclipse.ui.startup" 启动。 插件停止时会删除侦听器。

对首选项的任何更改都会导致打印 "PreferenceChangeEvent"。我抓住这一点来做我想做的实际工作;未显示。 如果创建了一个新的首选项节点(例如创建一个新的环境变量(Window > Preferences > C/C++ > Build > Environment)并按 Apply)然后打印 "PreferenceChangeEvent"。每当变量的值随后在首选项中更改时也会打印。

import org.eclipse.core.runtime.Platform;
import org.eclipse.core.runtime.preferences.IEclipsePreferences;
import org.eclipse.core.runtime.preferences.IPreferenceNodeVisitor;
import org.eclipse.core.runtime.preferences.IPreferencesService;
import org.eclipse.core.runtime.preferences.IEclipsePreferences.INodeChangeListener;
import org.eclipse.core.runtime.preferences.IEclipsePreferences.IPreferenceChangeListener;
import org.eclipse.core.runtime.preferences.IEclipsePreferences.NodeChangeEvent;
import org.eclipse.core.runtime.preferences.IEclipsePreferences.PreferenceChangeEvent;
import org.eclipse.jface.resource.ImageDescriptor;
import org.eclipse.ui.plugin.AbstractUIPlugin;
import org.osgi.framework.BundleContext;
import org.osgi.service.prefs.BackingStoreException;

public class Activator extends AbstractUIPlugin {

...

    public void start(BundleContext context) throws Exception {
        super.start(context);
        plugin = this;
        addPreferenceChangeListeners();
    }

    public void stop(BundleContext context) throws Exception {
        removePreferenceChangeListeners();
        plugin = null;
        super.stop(context);
    }

    private IPreferenceChangeListener fPreferenceChangeListener;
    private void addPreferenceChangeListeners() {
        /*
         * Create a single preference change listener; the same listener is
         * used for all the Preference Nodes.
         */
        fPreferenceChangeListener = new IPreferenceChangeListener() {
            @Override
            public void preferenceChange(PreferenceChangeEvent event) {
                System.err.println("PreferenceChangeEvent");
            }
        };

        IPreferencesService prefsService = Platform.getPreferencesService();
        IEclipsePreferences root = prefsService.getRootNode();
        /*
         * Create a visitor for adding the pref change listener to each node.
         */
        IPreferenceNodeVisitor addingVisitor = new IPreferenceNodeVisitor() {
            public boolean visit(IEclipsePreferences node) throws BackingStoreException {
                if(null!=fPreferenceChangeListener) {
                    System.out.println("Adding pref change listener");
                    node.addPreferenceChangeListener(fPreferenceChangeListener);
                    /*
                     * Add a addNodeChangeListener so that if any new preference nodes
                     * are added they will also have our listener added too. 
                     */
                    node.addNodeChangeListener(new INodeChangeListener() {
                        @Override
                        public void removed(NodeChangeEvent event) {
                            System.out.println("removed: event=" + event.toString());
                        }
                        @Override
                        public void added(NodeChangeEvent event) {
                            System.out.println("added: event=" + event.toString());
                            IEclipsePreferences node = (IEclipsePreferences) event.getChild();
                            node.addPreferenceChangeListener(fPreferenceChangeListener);
                        }
                    });
                }
                return true;
            }
        };

        /*
         * Add the listener to the root and all its children
         */
        try {
            root.accept(addingVisitor);
        } catch (BackingStoreException e) {
            e.printStackTrace();
        }
    }

    private class PreferenceChangeRemovingVisitor implements IPreferenceNodeVisitor {
        @Override
        public boolean visit(IEclipsePreferences node) {
            if(null!=fPreferenceChangeListener) {
                System.out.println("Removing pref change listener");
                node.removePreferenceChangeListener(fPreferenceChangeListener);
            }
            return true;
        }
    }

    private void removePreferenceChangeListeners() {
        IPreferencesService prefsService = Platform.getPreferencesService();
        IEclipsePreferences root = prefsService.getRootNode();
        IPreferenceNodeVisitor removingVisitor = new PreferenceChangeRemovingVisitor(); 
        try {
            root.accept(removingVisitor);
        } catch (BackingStoreException e) {
            e.printStackTrace();
        }
        fPreferenceChangeListener = null;
    }
}