【问题标题】:Running SWT based, cross-platform jar properly on a Mac在 Mac 上正确运行基于 SWT 的跨平台 jar
【发布时间】:2010-10-20 09:21:07
【问题描述】:

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

到目前为止,我已经设法解决了由于 SWT 依赖的系统特定库而出现的导出问题(请参阅相关的 thread)。生成的 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$1.<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$1.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

我检查了一些相关线程:(Can't get SWT Display on Mac OS X, Problems With SWT on Mac) 以及UI Thread entry on the SWT FAQ 以及Bringing your Java App to MacDeploying SWT applications on Mac OSX 等教程。

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

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

提前致谢,

【问题讨论】:

标签: java macos cross-platform swt


【解决方案1】:

是的,你肯定需要-XstartOnFirstThread 才能让它在 Mac OS X 上运行。因为它是一个 VM 参数,你只能在启动应用程序时指定它,所以从你的代码中检测操作系统并设置它是否是 Mac OS X 是不可能的。 solution on the Eclipse site 创建一个适当的 Mac OS X My Application.app,它是特定于平台的,同样,在您的情况下不可行。

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

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

更新 2: 正如 cmets 中所指出的,有一个 tutorial on deploying SWT applications with Java Web Start。我只是在 Mac OS X (10.6.x) 上启动了 JNLP,它就可以工作了。查看example 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>

注意最后的&lt;extension href="swt.jnlp"/&gt; 行,指向platform-specific SWT JNLP file(这里省略了一些部分):

<?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>

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

【讨论】:

  • 您的建议(在 JNLP 文件中指定)听起来很酷,有人可以否认或确认吗??
  • 在这里回答我自己的问题; -XstartOnFirstThread 参数显然是 linux64 (sun-jdk-1.6.0) 上无法识别的选项,导致执行失败:> java -jar -XstartOnFirstThread dist/test.jar 无法识别的选项:-XstartOnFirstThread 无法创建 Java 虚拟机。 [2]+ 杀死java -jar dist/test.jar
  • @posdef:很有趣,显然 Windows 32 位 VM 不如 Linux 64 位版本那么挑剔。无论如何,这意味着您必须拥有两个不同的 JNLP,如上所示。
  • @Zsolt:嗯,如何检查 JNLP 文件中的操作系统并相应地传递参数,如此处所写 (eclipse.org/swt/jws)?它应该工作正常吗?请注意,他们出于其他原因使用操作系统检查。
  • @posdef:很好的发现,查看引用的 swt.jnlp 发现您确实可以做到这一点。查看更新的答案。
【解决方案2】:

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

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

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

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

【讨论】:

  • 这个理论是有道理的,但我很困惑为什么它会成为 Mac 环境特有的问题。此外,由于我不是编写 GUI 的人,我不知道软件中的哪个位置可能存在“从非 UI 线程调用 UI 方法”,这使得问题变得更加复杂。
  • 您的评论在这种情况下没有意义,因为调用 Display.getDefault() 时会发生异常。
猜你喜欢
  • 1970-01-01
  • 2011-01-03
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-12-13
  • 1970-01-01
  • 2012-01-05
相关资源
最近更新 更多