Java 将SWT.OpenDocument SWT Listener添加到RCP应用程序的e4应用程序
我想使用eclipse的launcher.openfile特性。因此,我阅读了一些文档(例如) 我正确地实现了一个自定义应用程序类,但是我猜这个类的内容缺少了一些东西,因为在我的生命周期类中再也找不到主窗口,这通常可以在我使用标准应用程序时找到 如何使用E4Application类的通用功能,只添加SWT侦听器SWT.OpenDocument 这里是我的申请代码:Java 将SWT.OpenDocument SWT Listener添加到RCP应用程序的e4应用程序,java,eclipse,eclipse-rcp,e4,Java,Eclipse,Eclipse Rcp,E4,我想使用eclipse的launcher.openfile特性。因此,我阅读了一些文档(例如) 我正确地实现了一个自定义应用程序类,但是我猜这个类的内容缺少了一些东西,因为在我的生命周期类中再也找不到主窗口,这通常可以在我使用标准应用程序时找到 如何使用E4Application类的通用功能,只添加SWT侦听器SWT.OpenDocument 这里是我的申请代码: package de.port.dsntool.ui.services; import org.eclipse.core.runt
package de.port.dsntool.ui.services;
import org.eclipse.core.runtime.IProduct;
import org.eclipse.core.runtime.Platform;
import org.eclipse.equinox.app.IApplication;
import org.eclipse.equinox.app.IApplicationContext;
import org.eclipse.swt.SWT;
import org.eclipse.swt.widgets.Display;
import org.eclipse.ui.PlatformUI;
public class MyE4Application implements IApplication{
//Application with Listener to SWT.OpenDocument
private Display display = null;
public Display getApplicationDisplay() {
if (display == null) {
display = Display.getDefault();
}
return display;
}
@Override
public Object start(IApplicationContext context) throws Exception {
System.out.println("START My Application");
OpenDocumentEventProcessor openDocProcessor =
new OpenDocumentEventProcessor();
IProduct product = Platform.getProduct();
if (product != null && product.getName() != null) {
Display.setAppName(product.getName());
}
Display display = getApplicationDisplay();
display.addListener(SWT.OpenDocument, openDocProcessor);
try {
int returnCode = PlatformUI.createAndRunWorkbench(display, new
ApplicationWorkbenchAdvisor(openDocProcessor));
if (returnCode == PlatformUI.RETURN_RESTART) {
return IApplication.EXIT_RESTART;
}
return IApplication.EXIT_OK;
} finally {
if (display != null)
display.dispose();
}
}
@Override
public void stop() {
// TODO Auto-generated method stub
}
}
ApplicationWorkbenchHadVisor.java:
package my.package;
import org.eclipse.swt.widgets.Display;
import org.eclipse.ui.application.WorkbenchAdvisor;
public class ApplicationWorkbenchAdvisor extends WorkbenchAdvisor {
private OpenDocumentEventProcessor openDocProcessor;
public ApplicationWorkbenchAdvisor(
OpenDocumentEventProcessor openDocProcessor) {
this.openDocProcessor = openDocProcessor;
}
@Override
public void eventLoopIdle(Display display) {
openDocProcessor.openFiles();
super.eventLoopIdle(display);
}
@Override
public String getInitialWindowPerspectiveId() {
// TODO Auto-generated method stub
return null;
}
}
OpenDocumentEventProcessor.java:
package my.package;
import java.util.ArrayList;
import org.eclipse.swt.widgets.Event;
import org.eclipse.swt.widgets.Listener;
public class OpenDocumentEventProcessor implements Listener {
private ArrayList<String> filesToOpen = new ArrayList<String>(1);
@Override
public void handleEvent(Event event) {
if (event.text != null)
filesToOpen.add(event.text);
}
public void openFiles() {
if (filesToOpen.isEmpty())
return;
String[] filePaths = filesToOpen.toArray(
new String[filesToOpen.size()]);
filesToOpen.clear();
for (String path : filePaths) {
// open the file path
}
}
}
编辑
我在我的生命周期和EventloopAdvisor中使用PostContextCreate函数实现了您的解决方案@greg-449。
但我发现了一个奇怪的bug:只有在PostContextCreate中实现侦听器之前或之后打开对话框时,此解决方案才有效:
这是我生命周期中的实际代码片段:
@PostContextCreate
public void postContextCreate(final IEclipseContext context) {
final Shell shell = new Shell(Display.getCurrent());
new LicenseAgreementDialog(shell).open();
if(!shell.isDisposed())
shell.dispose();
OpenDocumentEventProcessor openDocProcessor = new OpenDocumentEventProcessor();
Display display = Display.getCurrent();
display.addListener(SWT.OpenDocument, openDocProcessor);
IEventLoopAdvisor eventLoopAdvisor = new EventLoopAdvisor(openDocProcessor);
context.set(IEventLoopAdvisor.class, eventLoopAdvisor);
}
类LicenseAgreementDialog
在RCP应用程序启动之前(在splashscreen加载时打开)仅打开一次对话框,在应用程序启动之后,SWT.OpenDocument事件由其他双击的项目文件正确触发。但是,当我关闭rcp应用程序并再次启动它时,LicenseAgreementDialog
不会再次正确打开,因此不会再触发任何SWT.OpenDocument事件。
我测试了这个bug,找到了一个解决方案,我总是必须在@PostContextCreateFunction
中打开一个对话框,否则不会触发SWT.OpenDocument事件。我还使用了一个普通的MessageDialog
(->MessageDialog.openInformation(newshell(Display.getCurrent()),“Opening”,“Now”);
)来测试它,而不是LicenseAgreementDialog
,它在每次启动时都会打开,但之前没有任何对话框
是否有可能避免总是打开一个虚拟对话框来触发事件
最终编辑
经过大量的尝试和错误,我终于找到了一个可以接受的解决方案,以避免在开始时出现这个虚拟对话框:我使用了添加readAndDispatch循环的提示,直到它为false,但是这个循环本身并没有什么区别。我不得不添加第二个循环,等待readAndDispatch返回true。我以不同的顺序测试了两个循环,以此类推,但这是唯一有效的解决方案:
@PostContextCreate
public void postContextCreate(final IEclipseContext context,
final IEventBroker eventBroker) {
final Shell shell = new Shell(Display.getCurrent());
new LicenseAgreementDialog(shell).open();
/*check for clicked project file or only launcher.exe
* when only launcher.exe is clicked there are no cmd arguments
* when project file is double clicked and gets opened by file handler
* the one and only cmd arg is the filepath from the clicked project file */
if(Platform.getCommandLineArgs().length != 0) {
while(Display.getCurrent().readAndDispatch()) { /* wait for false */ }
while(!Display.getCurrent().readAndDispatch()) { /* wait for true */ }
}
if(!shell.isDisposed())
shell.dispose();
OpenDocumentEventProcessor openDocProcessor = new OpenDocumentEventProcessor(eventBroker);
Display display = Display.getCurrent();
display.addListener(SWT.OpenDocument, openDocProcessor);
IEventLoopAdvisor eventLoopAdvisor = new EventLoopAdvisor(openDocProcessor);
context.set(IEventLoopAdvisor.class, eventLoopAdvisor);
}
通过这两个循环,SWT.OpenDocument事件总是被正确触发,即使我以前没有显示对话框。谢谢你的帮助@greg-449
下面是我已经得到的一点提示:.ini文件必须具有-name属性,当您将openfile功能与SWT.OpenDocument事件一起使用时,该属性必须与独立的RCP应用程序主窗口标签相匹配(对于我来说,我使用产品名称作为窗口标签):
当您的主窗口标签为例如:My Rcp App时
然后,launcher.ini文件必须具有具有相同字符串的-name属性:
--launcher.defaultAction
openFile
-name
My Rcp App
或者您使用变量作为rcp应用程序的产品名称:
--launcher.defaultAction
openFile
-name
%product.name
使用
PlatformUI.createAndRunWorkbench
使您的RCP成为3.x兼容模式RCP,它使用LegacyIDE.e4xmi,因此找不到您的窗口
我认为对于纯e4 RCP,您可能只需在生命周期中设置侦听器,并使用IEventLoopAdvisor
因此,删除MyE4Application并使用标准的E4Application。还应删除ApplicationWorkbenchHadVisor
在生命周期中设置内容@PostContextCreate
@PostContextCreate
public void postContextCreate(final IEclipseContext context)
{
OpenDocumentEventProcessor openDocProcessor = new OpenDocumentEventProcessor();
Display display = Display.getCurrent();
display.addListener(SWT.OpenDocument, openDocProcessor);
IEventLoopAdvisor eventLoopAdvisor = new EventLoopAdvisor(openDocProcessor);
context.set(IEventLoopAdvisor.class, eventLoopAdvisor);
}
并使用如下事件循环顾问:
@SuppressWarnings("restriction")
class EventLoopAdvisor implements IEventLoopAdvisor
{
private final OpenDocumentEventProcessor openDoc;
EventLoopAdvisor(OpenDocumentEventProcessor openDoc)
{
this.openDoc = openDoc;
}
@Override
public void eventLoopIdle(final Display display)
{
openDoc.openFiles();
display.sleep();
}
@Override
public void eventLoopException(final Throwable exception)
{
// TODO handle errors
}
}
我不会真的称之为e4 RCP,它是一个3.x兼容模式RCP,使用一些底层e4功能。我想如果你使用
PlatformUI.createAndRunWorkbench
它将使用LegacyIDE.e4xmi
而不是你的应用程序。e4xmi请看我的编辑,在那里我解释了我的解决方案@greg-449I我想我帮不了多少忙。我使用macOS,甚至在Eclipse本身上也无法让launcher.openFile工作。一个猜测是循环调用Display.readAndDispatch,直到返回false代替对话框。我需要添加两个循环。第一个循环是您的猜测:调用Display.readAndDispatch直到返回false。第二个循环必须调用Display.readAndDispatch,直到返回true!(见我的最终编辑)
@SuppressWarnings("restriction")
class EventLoopAdvisor implements IEventLoopAdvisor
{
private final OpenDocumentEventProcessor openDoc;
EventLoopAdvisor(OpenDocumentEventProcessor openDoc)
{
this.openDoc = openDoc;
}
@Override
public void eventLoopIdle(final Display display)
{
openDoc.openFiles();
display.sleep();
}
@Override
public void eventLoopException(final Throwable exception)
{
// TODO handle errors
}
}