Правильный запуск кроссплатформенного фляги на базе SWT на Mac - PullRequest
23 голосов
/ 20 октября 2010

Я работал над проектом на основе SWT, который предназначен для развертывания как Java Web Start и, следовательно, для использования на нескольких платформах.

До сих пор мне удавалось решить проблему экспорта, возникающую из-за системных библиотек, от которых зависит SWT (см. Соответствующий поток ). Результирующий jar, похоже, отлично работает на 32/64-битных Linux и 64-битных окнах, однако на 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

Я проверил ряд соответствующих тем: ( Не удается получить SWT-дисплей в Mac OS X , Проблемы с SWT на Mac ), а также UI Запись в теме SWT FAQ и учебные пособия, такие как Перенос приложения Java на Mac и Развертывание приложений SWT на Mac OSX .

Насколько я понимаю, проблема связана с обработкой потоков в Mac OSX, и я должен попытаться реализовать аргумент JVM -XstartOnFirstThread при выполнении. Это правильно?

Предполагая, что мое понимание проблемы является точным, я немного запутался, поскольку это программное обеспечение предназначено для кроссплатформенности и работы на челюстях. Нужно ли мне создавать файл info.plist, если так, где в пакете и как, иначе как я могу «условно» передать этот аргумент в JVM во время выполнения?

Заранее спасибо,

Ответы [ 2 ]

36 голосов
/ 20 октября 2010

Да, вам определенно понадобится -XstartOnFirstThread, чтобы это работало в Mac OS X. Поскольку это параметр виртуальной машины, вы можете указать его только при запуске приложения, поэтому обнаружение ОС по вашему коду и установка его, если это Mac OS X не возможна. Решение на сайте Eclipse создает правильный Mac OS X My Application.app , который зависит от платформы и, опять же, не применим в вашем случае.

Однако я только что попытался запустить приложение Eclipse RCP в Windows XP с указанным аргументом -XstartOnFirstThread, и оно не жаловалось вообще. Это означает, что вы можете указать этот аргумент в своем файле JNLP, и, вероятно, он будет проигнорирован на всех других платформах и получен на Mac OS X.

ОБНОВЛЕНИЕ: Если по какой-то причине -XstartOnFirstThread вызывает проблемы на какой-либо платформе или вы просто хотите Делать правильные вещи , существует другое возможное решение. Вы можете обнаружить ОС пользователя в браузере - при условии, что приложение запускается с веб-страницы - и предоставить другую JNLP для Mac OS X и других платформ.

ОБНОВЛЕНИЕ 2: Как указано в комментариях, существует руководство по развертыванию приложений SWT с Java Web Start . Я просто запустил JNLP на Mac OS X (10.6.x), и это сработало. Глядя на пример 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>

Обратите внимание на строку <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>

В конце файла: специфический аргумент -XstartOnFirstThread для Mac OS X.

0 голосов
/ 20 октября 2010

SWT (как и любая другая структура пользовательского интерфейса) имеет «поток пользовательского интерфейса». Обычно это основной поток (то есть тот, который выполнял main(String[] args). Все вызовы методов пользовательского интерфейса должны происходить в этом потоке.

Если вам нужно вызвать метод пользовательского интерфейса из потока, не являющегося пользовательским интерфейсом, вы должны обернуть его:

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

Если вам нужно дождаться результата, вы можете использовать syncExec()

...