Java 在 Mac 上正确运行基于 SWT 的跨平台 jar

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/3976342/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-14 07:48:26  来源:igfitidea点击:

Running SWT based, cross-platform jar properly on a Mac

javamacoscross-platformswt

提问by posdef

I have been working on a SWT-based project which is intended to be deployed as Java Web Start, and thus be used on multiple platforms.

我一直在研究一个基于 SWT 的项目,该项目旨在部署为 Java Web Start,因此可以在多个平台上使用。

So far I have managed to tackle the exporting problem that arises due to the system-specific libraries SWT depends on (see relevant thread). The resultant jar seems to work start fine on 32/64-bit linux and 64-bit windows, however execution fails on a Mac with the following output:

到目前为止,我已经设法解决了由于 SWT 依赖的特定于系统的库而出现的导出问题(请参阅相关线程)。生成的 jar 似乎在 32/64 位 linux 和 64 位 Windows 上运行良好,但是在 Mac 上执行失败,输出如下:

$ java -jar dist/test.jar 
Adding { file:/Volumes/LaCie/ChiBE_Local/swt/swt-cocoa-macosx-x86_64-3.6.1.jar } to the classpath
***WARNING: Display must be created on main thread due to Cocoa restrictions.
Exception in thread "main" java.lang.reflect.InvocationTargetException
   at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
   at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
   at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
   at java.lang.reflect.Method.invoke(Method.java:597)
   at org.eclipse.jdt.internal.jarinjarloader.JarRsrcLoader.main(JarRsrcLoader.java:58)
Caused by: java.lang.ExceptionInInitializerError
   at org.eclipse.gef.tools.MarqueeSelectionTool.<init>(MarqueeSelectionTool.java:99)
   at org.gvt.MarqueeZoomTool.<init>(MarqueeZoomTool.java:16)
   at org.gvt.action.MarqueeZoomToolAction.<init>(MarqueeZoomToolAction.java:28)
   at org.gvt.action.MarqueeZoomToolAction.createTool(MarqueeZoomToolAction.java:28)
   at org.gvt.action.AbstractGEFToolAction.<init>(AbstractGEFToolAction.java:24)
   at org.gvt.action.MarqueeZoomToolAction.<init>(MarqueeZoomToolAction.java:20)
   at org.gvt.TopMenuBar.createBarMenu(TopMenuBar.java:113)
   at org.gvt.ChisioMain.createMenuManager(ChisioMain.java:617)
   at org.eclipse.jface.window.ApplicationWindow.addMenuBar(ApplicationWindow.java:235)
   at org.gvt.ChisioMain.main(ChisioMain.java:149)
   at org.gvt.RuntimeMain.main(RuntimeMain.java:14)
   ... 5 more
Caused by: org.eclipse.swt.SWTException: Invalid thread access
   at org.eclipse.swt.SWT.error(Unknown Source)
   at org.eclipse.swt.SWT.error(Unknown Source)
   at org.eclipse.swt.SWT.error(Unknown Source)
   at org.eclipse.swt.widgets.Display.error(Unknown Source)
   at org.eclipse.swt.widgets.Display.createDisplay(Unknown Source)
   at org.eclipse.swt.widgets.Display.create(Unknown Source)
   at org.eclipse.swt.graphics.Device.<init>(Unknown Source)
   at org.eclipse.swt.widgets.Display.<init>(Unknown Source)
   at org.eclipse.swt.widgets.Display.<init>(Unknown Source)
   at org.eclipse.swt.widgets.Display.getDefault(Unknown Source)
   at org.eclipse.swt.widgets.Display.run(Unknown Source)
   at org.eclipse.swt.graphics.Device.getDevice(Unknown Source)
   at org.eclipse.swt.graphics.Resource.<init>(Unknown Source)
   at org.eclipse.swt.graphics.Cursor.<init>(Unknown Source)
   at org.eclipse.draw2d.Cursors.<clinit>(Cursors.java:170)
   ... 16 more

I have checked a number of relevant threads: (Can't get SWT Display on Mac OS X, Problems With SWT on Mac) as well as the UI Thread entry on the SWT FAQand tutorials such as Bringing your Java App to Macand Deploying SWT applications on Mac OSX.

我已经查了一些相关的线程(在Mac OS X无法获得SWT显示问题在Mac SWT),以及在对SWT FAQ UI线程进入和教程,如使您的Java应用程序到Mac部署Mac OSX 上的 SWT 应用程序

It's my understanding that the problem originates from thread handling on Mac OSX, and I should try to implement the JVM argument -XstartOnFirstThreadat the execution. Is this right?

我的理解是问题源于 Mac OSX 上的线程处理,我应该尝试在执行时实现 JVM 参数-XstartOnFirstThread。这是正确的吗?

Assuming that my understanding of the problem is accurate, I am a bit confused as this software is intended to be cross-platform and run on javaws. Do I need to create an info.plistfile, if so where in the package and how, otherwise how can I "conditionally" pass that argument to JVM at the time of execution?

假设我对问题的理解是准确的,我有点困惑,因为该软件旨在跨平台并在 javaws 上运行。我是否需要创建一个info.plist文件,如果需要,在包中的何处以及如何创建,否则我如何在执行时“有条件地”将该参数传递给 JVM?

Thanks in advance,

提前致谢,

采纳答案by Zsolt T?r?k

Yes, you will definitely need -XstartOnFirstThreadto get this working on Mac OS X. Since it's a VM parameter, you can only specify it when launching your application, so detecting the OS from you code and setting it if it's Mac OS X is not possible. The solution on the Eclipse sitecreates a proper Mac OS X My Application.app, which is platform specific and, again, not feasible in your case.

是的,你肯定需要-XstartOnFirstThread让它在 Mac OS X 上运行。因为它是一个 VM 参数,你只能在启动应用程序时指定它,所以从你的代码中检测操作系统并在它是 Mac OS X 时设置它是不可能的。在Eclipse的现场解决方案创建了一个合适的Mac OS X我Application.app,这是特定于平台的,并再次,不要在你的情况下是可行的。

However, I just tried running an Eclipse RCP application on Windows XP with the -XstartOnFirstThreadargument specified, and it didn't complain at all. This means that you can specify this argument in your JNLP file and presumably it will be ignored on all other platforms and picked up on Mac OS X.

但是,我只是尝试使用-XstartOnFirstThread指定的参数在 Windows XP 上运行 Eclipse RCP 应用程序,它根本没有抱怨。这意味着您可以在 JNLP 文件中指定此参数,并且可能会在所有其他平台上被忽略并在 Mac OS X 上选取。

UPDATE:If for some reason -XstartOnFirstThreadcauses trouble on any platform, or you just want to Do The Right Thing, there is another possible solution. You could detect the user's OS in the browser — assuming that the application is launched from a web page —, and supply a different JNLP for Mac OS X and other platforms.

更新:如果由于某种原因-XstartOnFirstThread导致在任何平台上出现问题,或者您只想做正确的事情,还有另一种可能的解决方案。您可以在浏览器中检测用户的操作系统——假设应用程序是从网页启动的——并为 Mac OS X 和其他平台提供不同的 JNLP。

UPDATE 2:As pointed out in the comments, there is a tutorial on deploying SWT applications with Java Web Start. I simply launched the JNLP on Mac OS X (10.6.x), and it worked. Looking at the example JNPLI found the following:

更新 2:正如评论中所指出的,有一个关于使用 Java Web Start 部署 SWT 应用程序教程。我只是在 Mac OS X (10.6.x) 上启动了 JNLP,并且成功了。查看示例 JNPL我发现以下内容:

<?xml version="1.0" encoding="utf-8"?>
<jnlp spec="1.0+"
    codebase="http://www.eclipse.org/swt/jws/"
    href="controlexample.jnlp">
<information>
      <title>Control Example</title>
      <vendor>eclipse.org</vendor>
      <homepage href="http://www.eclipse.org/swt/jws/" />
      <description>A demonstration of SWT Widgets</description>
      <description>Control Example</description>
</information>

<security>
    <all-permissions />
</security>

<resources>
    <extension href="swt.jnlp"/>
    <jar href="controlexample.jar" />
</resources>

<application-desc main-class="org.eclipse.swt.examples.controlexample.ControlExample" />
</jnlp>

Note the <extension href="swt.jnlp"/>line towards the end, pointing to the platform-specific SWT JNLP file(some parts omitted here):

请注意<extension href="swt.jnlp"/>末尾的行,指向特定平台的 SWT JNLP 文件(此处省略了某些部分):

<?xml version="1.0" encoding="utf-8"?>
<jnlp spec="1.0+"
    codebase="http://www.eclipse.org/swt/jws/"
    href="swt.jnlp">
<information>
      <title>SWT</title>
      <vendor>eclipse.org</vendor>
      <homepage href="http://www.eclipse.org/swt/jws/" />
      <description>SWT</description>
</information>

<security>
    <all-permissions />
</security>

<resources os="Windows" arch="x86">
    <j2se version="1.4+" />
    <jar href="swt-win32-windows-x86.jar" />
</resources>

...

<resources os="Mac\ OS\ X">
    <j2se version="1.5*" java-vm-args="-XstartOnFirstThread"/>
    <jar href="swt-carbon-osx-universal.jar" />
</resources>

<component-desc/>
</jnlp>

There it is towards the end of the file: the Mac OS X specific -XstartOnFirstThreadargument.

它在文件末尾:Mac OS X 特定-XstartOnFirstThread参数。

回答by Aaron Digulla

SWT (like any other UI framework) has a "UI thread". That is usually the main thread (i.e. the one that executed main(String[] args). All calls to UI methods must happen in this thread.

SWT(像任何其他 UI 框架一样)有一个“UI 线程”。那通常是主线程(即执行的那个main(String[] args)。对 UI 方法的所有调用都必须在该线程中发生。

If you need to call a UI method from a non-UI thread, you must wrap it:

如果需要从非 UI 线程调用 UI 方法,则必须对其进行包装:

Display.getDefault().asyncExec( new Runnable() { 
    public void run() {
         //ui call here
    }
} );

If you need to wait for the result, you can use syncExec()

如果需要等待结果,可以使用 syncExec()