使SWT/JFace支持跨平台
由于SWT的实现机制,在不同平台下,必须引用不同swt*.jar. 由于这个瓶颈,我们要为不同的平台编译不同的版本。但是这是可以避免的。这将是本文要讨论的内容。
我一共google到了3种solution:
1,使用swtjar.jar。
http://mchr3k.github.io/swtjar/
其主页有详细的介绍。但是似乎下载链接已经无效了,一个下载的办法是从github上找到引用了它的项目,比如https://github.com/mchr3k/org.intrace/tree/3a1debcbb831f802219b341fb5e37467b365d443/org.intrace/lib
swtjar.jar的原理,似乎是通过替换掉默认的ClassLoader来实现的。
根据我的测试,使用swtjar.jar的方案,如果引用到JFace,就没办法成功load jface classes。原因我之后会讲到。
这个方案我读过代码,但是没有试过,看起来很复杂,但是似乎功能也很健全,有兴趣的可以读一下。
3,http://stackoverflow.com/questions/2706222/create-cross-platform-java-swt-application
这个方案最简单明了,本文主要介绍该方案
其实3种方案实质是一样的,把所有平台的swt*.jar都打包进程序,然后根据OS和CPU构架信息,来动态load对应的swt*.jar
第三种Solution
我们所要介绍的第三种solution,它的办法是,在load class阶段,不load swt*.jar。而是延迟到main函数执行阶段,再根据OS和CPU构架来”手动地”load正确的swt*.jar
1) 首先添加以下方法
private static void loadSwtJar() {
String swtFileName="";
try {
String osName = System.getProperty("os.name").toLowerCase();
String osArch = System.getProperty("os.arch").toLowerCase();
final ClassLoader parentClassLoader = Thread.currentThread().getContextClassLoader();
Method addUrlMethod = URLClassLoader.class.getDeclaredMethod("addURL", URL.class);
addUrlMethod.setAccessible(true);
String swtFileNameOsPart =
osName.contains("win") ? "win32.win32" :
osName.contains("mac") ? "cocoa.macosx" :
osName.contains("linux") || osName.contains("nix") ? "gtk.linux" :
""; // throw new RuntimeException("Unknown OS name: "+osName)
String swtFileNameArchPart = osArch.contains("64") ? "x86_64" : "x86";
swtFileName = "org.eclipse.swt."+swtFileNameOsPart+"."+swtFileNameArchPart+"-4.4.jar";
URL swtFileUrl = new URL("rsrc:"+swtFileName); // I am using Jar-in-Jar class loader which understands this URL; adjust accordingly if you don't
addUrlMethod.invoke(parentClassLoader, swtFileUrl);
}
catch(Exception e) {
System.out.println("Unable to add the swt jar to the class path: "+swtFileName);
e.printStackTrace();
}
}
其作用是来根据OS和CPU构架信息,“手动地”加载正确的swt*.jar文件。
(以上代码在调试环境下可能没办法正确运行,需要在开始处添加一句:
URL.setURLStreamHandlerFactory(new RsrcURLStreamHandlerFactory(parentClassLoader));
但是在用ant编译时,则必须把这句话去掉。因为ant编译出的代码,RsrcURLStreamHandlerFactory已经被设置到URL,重复设置将出异常。其具体原因我就不深究了)
2) 添加jar-in-jar-loader.jar引用。
在eclipse的plugins目录下找到org.eclipse.jdt.ui_*version_number*.jar,解压它,发现jar-in-jar-loader.zip, 重命名为jar-in-jar-loader.jar。放到项目的lib目录下并引用。
需要添加这个jar的原因是,loadSwtJar方法隐式地使用了位于其中的JarRsrcLoader.class和相关的类。
3)在main函数最开始处添加 loadSwtJar()调用。
4)修改build.xml文件。
是的,你需要一个build.xml文件,如果没有,用eclipse的导出jar的功能生成一个。 修改build.xml文件的主要目的有2个:1是把SWT*.jar从默认加载列表中去掉,2是把所有平台的的SWT*.jar都放到打包列表中去。一加一减。给个例子:
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<project default="create_run_jar" name="Create Runnable Jar for Project swtguiexample with Jar-in-Jar Loader">
<!--this file was created by Eclipse Runnable JAR Export Wizard-->
<!--ANT 1.7 is required
-->
<target name="create_run_jar">
<jar destfile="/home/binhua/Desktop/ bin /swtguiexample.jar">
<manifest>
<attribute name="Main-Class" value="org.eclipse.jdt.internal.jarinjarloader.JarRsrcLoader"/>
<attribute name="Rsrc-Main-Class" value=" swtguiexample.Main"/>
<attribute name="Class-Path" value="."/>
<attribute name="Rsrc-Class-Path" value="./ jar-in-jar-loader.jar org.eclipse.equinox.common-3.6.100.v20120522-1841.jar org.eclipse.core.commands-3.6.1.v20120521-2329.jar org.eclipse.osgi-3.8.0.v20120529-1548.jar"/>
</manifest>
<zipfileset src="lib/jar-in-jar-loader.jar"/>
<fileset dir="/home/binhua/Desktop/code/swtexample/src/swtguiexample/target/classes"/>
<zipfileset dir="/home/binhua/.m2/repository/org/eclipse/swt/org.eclipse.swt.gtk.linux.x86_64/4.4" includes="org.eclipse.swt.gtk.linux.x86_64-4.4.jar"/>
<zipfileset dir="/home/binhua/.m2/repository/org/eclipse/swt/org.eclipse.swt.gtk.linux.x86/4.4" includes="org.eclipse.swt.gtk.linux.x86-4.4.jar"/>
<zipfileset dir="/home/binhua/.m2/repository/org/eclipse/swt/org.eclipse.swt.cocoa.macosx.x86_64/4.4" includes="org.eclipse.swt.cocoa.macosx.x86_64-4.4.jar"/>
<zipfileset dir="/home/binhua/.m2/repository/org/eclipse/swt/org.eclipse.swt.win32.win32.x86_64/4.4" includes="org.eclipse.swt.win32.win32.x86_64-4.4.jar"/>
<zipfileset dir="/home/binhua/.m2/repository/org/eclipse/swt/org.eclipse.swt.win32.win32.x86/4.4" includes="org.eclipse.swt.win32.win32.x86-4.4.jar"/>
<zipfileset dir="/home/binhua/.m2/repository/org/eclipse/equinox/org.eclipse.equinox.common/3.6.100.v20120522-1841" includes="org.eclipse.equinox.common-3.6.100.v20120522-1841.jar"/>
<zipfileset dir="/home/binhua/.m2/repository/org/eclipse/core/org.eclipse.core.commands/3.6.1.v20120521-2329" includes="org.eclipse.core.commands-3.6.1.v20120521-2329.jar"/>
<zipfileset dir="/home/binhua/.m2/repository/org/eclipse/osgi/org.eclipse.osgi/3.8.0.v20120529-1548" includes="org.eclipse.osgi-3.8.0.v20120529-1548.jar"/>
</jar>
</target>
</project>
以上: 1,在Rsrc<attribute name="Rsrc-Class-Path" 中,删除掉SWT*.jar,2,添加所有的平台的SWT*.jar到zipfileset节点。
5) 好了,用ant编译吧。
Trouble Shooting
以下trouble shooter事实上才是成败的关键:
#1
如果代码中引用了JFace*.jar,那么以上Solution会报ClassNotFoundException,说JFace下的某个类找不到,这是因为JFace加载失败了,为什么呢。
因为JFace*.jar还是默认加载的,JFace依赖于SWT*.jar,SWT*.jar已经延迟加载了,自然,JFace*.jar不可能加载成功。
解决办法是让JFace也延迟加载:
1,在Build.xml的Rsrc<attribute name="Rsrc-Class-Path" 中,把JFace*.jar也去掉
2,在loadSwtJar()最后一行添加
private static void loadSwtJar() {
…
addUrlMethod.invoke(parentClassLoader, new URL("rsrc:org.eclipse.jface-3.8.0.v20120521-2329.jar"));
}
2#
如果你有以下代码
public class MyApplicationWindow extends ApplicationWindow implements IExceptionHandler{
…
public static void main( String[] args )
{
loadSwtJar();
…
}
}
也会报ClassNotFoundException,为什么呢?
因为ApplicationWindow 和IExceptionHandler都是JFace下的类,main函数放在MyApplicationWindow中,要执行main函数,首先要加载ApplicationWindow 和IExceptionHandler,而这个时候,JFace还没被加载呢,记得吗,它被延迟加载了。
解决办法很简单,把main函数挪挪地方就好了。
3#
如果在Mac OS X下执行出错,因为必须加一个参数:
java -XstartOnFirstThread -jar *.jar
恩,不要问我为什么。
使SWT/JFace支持跨平台的更多相关文章
- 简介SWT Jface
可以使用标准窗口小部件工具箱(Standard Widget Toolkit,SWT)和 JFace 库来开发用于 Eclipse 环境的图形用户界面,而且还可以将它们用于开发单独的 GUI 本机应用 ...
- paip.java gui swt/jface 最佳实践
paip.java gui swt/jface 最佳实践 1. 工具:Eclipse +jigloo4 1 2. 安装插件: 1 1. IMPORT swt lib 2 2. 新建立窗体 2 3. 运 ...
- Adobe Edge Animate –修改Edge Commons Spotlight功能,使之能支持播放中国网站视频
Adobe Edge Animate –修改Edge Commons Spotlight功能,使之能支持播放中国网站视频 版权声明: 本文版权属于 北京联友天下科技发展有限公司. 转载的时候请注明版权 ...
- MyEclipse中配置SWT/JFace/SWT-Designer 艰辛路程
我最近受一个老师所托,写一个小系统,为了更加熟练使用Java,我决定用Java写一个PC软件. 我是一个比较追求完美的孩子,所以虽然老师对界面没啥要求,但是为了加快速度和界面美观,果断选择SWT/JF ...
- Gaea是支持跨平台具有高并发、高性能、高可靠性,并提供异步、多协议、事件驱动的中间层服务框架
Gaea是支持跨平台具有高并发.高性能.高可靠性,并提供异步.多协议.事件驱动的中间层服务框架 Gaea:58同城开源的中间层服务框架 https://github.com/58code/Gaea 中 ...
- vs中开发web站点使IIS Express支持局域网连接
vs中开发web站点使IIS Express支持局域网连接 在开发webapi的时候,客户端设备都会使用局域网的地址访问webapi,有时候需要调试api.这个时候就需要使用一些技巧了,这里我记录了我 ...
- PIE使IE浏览器支持CSS3属性(圆角、阴影、渐变)
http://www.360doc.com/content/12/1214/09/11181348_253939277.shtml PIE使IE浏览器支持CSS3属性(圆角.阴影.渐变) 2012-1 ...
- Data.FireDACJSONReflect单元不支持跨平台
Data.FireDACJSONReflect不支持跨平台 Data.FireDACJSONReflect里面:IFDJSONDeltasApplyUpdates,TFDJSONDeltas,TFDJ ...
- vcl.Forms等与VCL界面有关的单元不支持跨平台
vcl.Forms等与VCL界面有关的单元不支持跨平台 midaslib也不支持
随机推荐
- JAVASE02-Unit08: 文本数据IO操作 、 异常处理
Unit08: 文本数据IO操作 . 异常处理 * java.io.ObjectOutputStream * 对象输出流,作用是进行对象序列化 package day08; import java.i ...
- Android 基于Android的手机邮件收发(JavaMail)之四(邮件的发送)
上一个邮件的接受,因为不当操作,保存未完成,一切东西都得从头开始那就先从邮件发送来吧. 先下我们做一个较为简单的邮件发送 以下是源代码:相信看过上篇文章所给连接的人,对于javamail应该都有了一定 ...
- linq实现数组转符号分割的字符串(备忘)
fitemidstr = string.Join(",", detailpre1.Select(i => i.Key.ToString()).ToArray());
- Git过滤文件和文夹
今天是2016年10月份的最后一天,感觉时间过得真的是飞快呢,此刻天下着小雨,天气灰蒙如天每个人的心情一样.在此把这个月的项目上传到git上,就需要过滤一些项目自动生成的不必要的文件,如:bin,ob ...
- MWeb 1.4 新功能介绍二:静态博客功能增强
MWeb 比较有特色的是一键生成静态博客功能,然后从 MWeb 最开始规划要做静态博客生成功能时,我就希望 MWeb 的静态博客生成功能在易用的同时,还要有很强大的扩展性. 比如说能自己增加网站公告, ...
- java代码打包成jar以及转换为exe
教你如何把java代码打包成jar文件以及转换为exe可执行文件 1.背景: 学习java时,教材中关于如题问题,只有一小节说明,而且要自己写麻烦的配置文件,最终结果却只能转换为jar文件.实在是心有 ...
- Python爬虫爬取百度贴吧的图片
根据输入的贴吧地址,爬取想要该贴吧的图片,保存到本地文件夹,仅供参考: #!/usr/bin/python#_*_coding:utf-8_*_import urllibimport urllib2i ...
- 最好的cpm广告联盟哪里有
最好的cpm广告联盟哪里有,58传媒广告联盟还要提醒众位站长的是网站在经营发展中必须最大化的扩展自己的优势力量.每个网站都有属于自己的优势魅力,这些优势特点只有得到最大化的发挥才能为网站带来意想不到的 ...
- Java多线程开发系列之四:玩转多线程(线程的控制1)
在前文中我们已经学习了:线程的基本情况.如何创建多线程.线程的生命周期.利用已有知识我们已经可以写出如何利用多线程处理大量任务这样简单的程序.但是当应用场景复杂时,我们还需要从管理控制入手,更好的操纵 ...
- Notepad++自动刷新文本
现在的日志信息往往都是打印在硬盘上,而不是保存到线上,所以我们常常会使用notepad++来查看硬盘上的文本文件 这时往往会出现两个问题 (1)在notepad++长时间最小化后,再次打开会提示是否下 ...