【问题标题】:How to make multiple windows in Eclipse RCP e4如何在 Eclipse RCP e4 中制作多个窗口
【发布时间】:2016-08-04 22:40:43
【问题描述】:

我们想要实现一个可能有多个窗口的 RCP 应用程序 (MWindow) 对于不同的数据。 Windows 必须是独立的(不像新的 Eclipse IDE 窗口菜单项),但必须可以从 一个窗口进入另一个窗口。想象一个像 Word 这样的应用程序,您可以在其中 打开多个文档。我们尝试了各种方法,但它很安静 很难找到正确的 e4 方式:

1。为每个窗口创建一个新的 E4Application

我们的第一个方法是为每个应用程序创建并运行一个全新的 E4Application 新窗户。但这听起来不是正确的 e4 方式。它也是越野车:钥匙 绑定无法正常工作,并且每个新的都调用 LifecycleManager 应用程序,因此对于每个新窗口,不应该。

E4Application application = new E4Application();
BundleContext context = InternalPlatform.getDefault().getBundleContext();
ServiceReference<?> appContextService = context.getServiceReference(IApplicationContext.class);
IApplicationContext iac = (IApplicationContext) context.getService(appContextService);
IWorkbench workbench = application.createE4Workbench(iac, display);
 final E4Workbench implementation = (E4Workbench) workbench;
implementation.createAndRunUI(workbench.getApplication());

这似乎不是正确的做法。

2。 Eclipse IDE 方法

在 Eclipse IDE 中,您可以转到菜单并单击 Window -&gt; New Window 将打开一个全新的顶层窗口。但它是同步的:打开 两个窗口中的相同文本文件并在第一个窗口中编辑它会改变它 另一个也是。尽管我们通过简单地复制和粘贴来尝试这种方法 来自org.eclipse.ui.actions.OpenInNewWindowAction#run()

// Does not work because we do not have the RCP3 workbench in RCP4.
final IWorkbench workbench = PlatformUI.getWorkbench();
final IWorkbenchWindow workbenchWindow = workbench.getActiveWorkbenchWindow();
final IWorkbenchPage activePage = workbenchWindow.getActivePage();
final String perspectiveId;

if (activePage != null && activePage.getPerspective() != null) {
    perspectiveId = activePage.getPerspective().getId();
} else {
    perspectiveId = workbenchWindow.getWorkbench().getPerspectiveRegistry().getDefaultPerspective();
}

workbenchWindow.getWorkbench().openWorkbenchWindow(perspectiveId, null);

Eclipse IDE 似乎使用了 RCP3 兼容层。我们没有 找到了获取IWorkbench 对象的方法。既不由 PlatformUI#getWorkbench(),也不是通过应用程序上下文,也不是包 上下文。

3。克隆主窗口

我们偶然发现了Opening multiple instances of an MTrimmedWindow complete with perspectives etc n-mtrimmedwindow-complete-with-perspectives-etc 并做了很多试验和 错误并想出了这个泥泞的代码:

class ElementCloningBasedCreator {

    EModelService models = ...; // injected
    MApplication app = ...; // injected

    public void openNewWindow() {
        MWindow originWindow = (MWindow) models.find("the.main.window.id", app);
        MWindow newWindow = (MWindow) models.cloneElement(originWindow, null);

        MPerspectiveStack newPerspectiveStack =
            (MPerspectiveStack) models.find(the.main.perspective.stack.id, newWindow);
        newPerspectiveStack.setParent((MElementContainer) newWindow);

        addTo(app, newWindow);

        // Clone the shared elements. If we don't do that the rendering somewhere 
        // deep in the rabbit hole throws assertion erros because the recurisve 
        // finding of an element fails because the search root is null.
        for (final MUIElement originSharedElement : originWindow.getSharedElements()) {
            final MUIElement clonedSharedElement = models.cloneElement(originSharedElement, null);
            clonedSharedElement.setParent((MElementContainer) newWindow);
            newWindow.getSharedElements().add(clonedSharedElement);
        }

        cloneSnippets(app, originWindow, newPerspectiveStack, newWindow);
        newWindow.setContext(createContextForNewWindow(originWindow, newWindow));
        newWindow.setToBeRendered(true);
        newWindow.setVisible(true);
        newWindow.setOnTop(true);
        models.bringToTop(newWindow);
    }

    @SuppressWarnings({ "rawtypes", "unchecked" })
    private void addTo(MElementContainer target, MUIElement child) {
        child.setParent(target);
        target.getChildren().add(child);
    }

    /**
     * Clone each snippet that is a perspective and add the cloned perspective 
     * into the main PerspectiveStack.
     */
    private void cloneSnippets(MApplication app, MWindow originWindow,
        MPerspectiveStack newPerspectiveStack, MWindow newWindow) {
        boolean isFirstSnippet = true;

        for (MUIElement snippet : app.getSnippets()) {
            if (ignoreSnippet(snippet)) {
                continue;
            }

            String snipetId = snippet.getElementId();
            MPerspective clonedPerspective = 
                (MPerspective) models.cloneSnippet(app, snipetId, originWindow);
            findPlaceholdersAndCloneReferencedParts(clonedPerspective, newWindow);
            addTo(newPerspectiveStack, clonedPerspective);

            if (isFirstSnippet) {
                newPerspectiveStack.setSelectedElement(clonedPerspective);
                isFirstSnippet = false;
            }
        }
    }

    private boolean ignoreSnippet(MUIElement snippet) {
        return !(snippet instanceof MPerspective);
    }

    private void findPlaceholdersAndCloneReferencedParts(MPerspective clonedPerspective, MWindow newWindow) {
        List<MPlaceholder> placeholders = 
            models.findElements(clonedPerspective, null, MPlaceholder.class, null);

        for (MPlaceholder placeholder : placeholders) {
            MUIElement reference = placeholder.getRef();

            if (reference != null) {
                placeholder.setRef(models.cloneElement(placeholder.getRef(), null));
                placeholder.getRef().setParent((MElementContainer) newWindow);
            }
        }
    }
}

这段代码真的不起作用,我们真的需要一些提示/建议如何去做 没错,因为缺乏官方文件。开放的问题是:

  1. 我们是否需要克隆共享对象,如果不需要,我们如何防止 渲染过程中的错误)?
  2. 我们只看到了克隆元素所在的代码 通过getChildren().add() 添加到父级,但我们发现 孩子不会自动获得父母,但它是null。是不是 将父母也添加到孩子的正确模式?
  3. 我们深有感触 我们这样做是不对的。我们在这里做的事情看起来太复杂了。是 有更简单/更好的方法吗?

【问题讨论】:

标签: java eclipse eclipse-rcp e4


【解决方案1】:

您可以使用EModelService cloneSnippet 方法来执行此操作。

在 Application.e4xmi 的 Snippets 部分设计您的 MTrimmedWindow(或您想要的任何类型的窗口)。确保选中 To Be RenderedVisible 标志。您可能需要设置宽度和高度边界(您可能还需要设置 x 和 y 位置)。

您创建新窗口的命令处理程序就是:

@Execute
public void execute(EModelService modelService, MApplication app)
{
  MTrimmedWindow newWin = (MTrimmedWindow)modelService.cloneSnippet(app, "id of the snippet", null);

  app.getChildren().add(newWin);
}

【讨论】:

  • 谢谢,很好的提示。是不是不需要把应用设置为newWin的父应用?
  • 使用这种方法,我们遇到了 SWT 抱怨在 Application.e4xmi 中没有定义顶级窗口的问题。
  • 你需要在e4xmi的正常位置有一个主窗口。片段适用于第二个和后续窗口。在应用程序启动期间,可能可以从 sn-p 创建第一个窗口,但我还没有看到这样做。
  • 我们只有一种类型的窗口,是否有可能将其定义为 sn-p 并在 Application.e4xmi 中将此 sn-p 用于主窗口?
  • 正如我所说,在 LifeCycle 类中可能是可行的,但我还没有看到任何代码可以做到这一点。您还可以使用带有占位符的共享元素在不同的窗口之间共享内容。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2014-04-06
  • 2013-03-31
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-04-25
相关资源
最近更新 更多