使用注释在 Netbeans 平台上创建 window 个组

Creating window groups on Netbeans Platform with Annotations

已经回答了一个相关的 question,但是从那时起使用注释发生了很多变化。

我正在注册带有注释的 TopComponents。例如:

@TopComponent.Registration(mode = "explorer", openAtStartup = false,
        roles = "Test Role")

后来试过这样开群,作为测试:

    WindowManager.getDefault().invokeWhenUIReady(() -> {
        WindowManager.getDefault().getRegistry().getOpened().stream()
                .forEach((tc) -> {
                    tc.close();
                });
        TopComponentGroup group
                = WindowManager.getDefault()
                .findTopComponentGroup("Test Role");
        if (group != null) {
            group.open();
        }
    });

所有组件都已关闭,但没有打开任何组件。它不起作用,所以显然缺少一些管道。

这仍然是正确的做法吗?

有这方面的工作示例吗?

以下是我如何让它适用于遇到这个问题的任何人:

我创建了一个 class 并基于此 code 注册为服务:

/**
 * Based on code from: http://www.smartcode.ch/netbeans-hide-show-topcomponent/
 *
 * @author Javier A. Ortiz Bultrón javier.ortiz.78@gmail.com
 */
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
import org.openide.util.Lookup;
import org.openide.util.lookup.ServiceProvider;
import org.openide.windows.Mode;
import org.openide.windows.TopComponent;
import org.openide.windows.WindowManager;

@ServiceProvider(service = ViewManager.class)
public class ViewManager {

    private final Map<TopComponent, Mode> hiddenComponents;

    public ViewManager() {
        hiddenComponents = new HashMap<>();
    }

    public synchronized void showTopComponent(Class<? extends TopComponent> topComponentClass) {

        for (Map.Entry<TopComponent, Mode> hiddenComponentEntry : hiddenComponents.entrySet()) {
            TopComponent hiddenComponent = hiddenComponentEntry.getKey();

            if (hiddenComponent.getClass().equals(topComponentClass)) {
                Mode mode = hiddenComponentEntry.getValue();
                WindowManager.getDefault().findMode(mode.getName()).dockInto(hiddenComponent);
                hiddenComponent.open();
                hiddenComponents.remove(hiddenComponent);
                break;
            }

        }
    }

    public synchronized void hideTopComponent(Class<? extends TopComponent> topComponentClass) {

        Set<TopComponent> shownTopComponents = WindowManager.getDefault().getRegistry().getOpened();

        for (TopComponent shownTopComponent : shownTopComponents) {
            if (shownTopComponent.getClass().equals(topComponentClass)) {
                Mode mode = WindowManager.getDefault().findMode(shownTopComponent);

                hiddenComponents.put(shownTopComponent, mode);
                shownTopComponent.close();
            }
        }
    }

    public synchronized void showAll() {
        for (TopComponent tc : hiddenComponents.keySet()) {
            showTopComponent(tc.getClass());
        }
    }

    /**
     * Load a screen role.
     *
     * @param role Role to load.
     */
    public static void loadRole(String role) {
        //Open all components
        Lookup.getDefault().lookup(ViewManager.class).showAll();
        //Change role (this closes the ones not in this role)
        WindowManager.getDefault().setRole(role);
    }
}

然后在模块安装程序中我这样做:

@Override
    public void restored() {
        WindowManager.getDefault().invokeWhenUIReady(() -> {
            /**
             * All windows start opened. Populated the ViewManager. It is
             * important to configure all TopComponents with: 
             * persistenceType = TopComponent.PERSISTENCE_NEVER or TopComponent.PERSISTENCE_ONLY_OPENED
             * and openAtStartup = true
             */
            ViewManager manager = Lookup.getDefault().lookup(ViewManager.class);
            WindowManager.getDefault().getRegistry().getOpened().stream()
                    .forEach((tc) -> {
                        manager.hideTopComponent(tc.getClass());
                    });
            manager.loadRole(Tool.LOBBY);
        });
    }

如安装程序代码中所述,诀窍是将所有模块标记为在启动时打开并使用正确的持久性类型。

这将在应用程序启动时打开所有 windows,隐藏它们(同时在 ViewManager 上注册它们)然后打开指定的角色。

角色,如记录here,执行以下操作:

此方法的默认实现执行以下操作:

  1. 隐藏主要window。
  2. 保存当前window当前布局 角色。
  3. 从给定的角色加载新的 window 布局。
  4. 显示主要window.

另一种选择是覆盖 WindowManager 本身来完成所有这些,但我发现它过于具有侵入性和危险性,因为某些方法受到保护,因此不可能包装 WindowsManagerImpl(默认)。也不可能只扩展 WindowsManagerImpl,因为它的包是私有的。