开发人员和用户对Swing以及最大的Java编程语言的最大抱怨之一就是客户端应用程序感觉不像本机应用程序。 (本机应用程序是使用操作系统的内置库以编程语言编写的应用程序,例如在Windows上运行的Visual C ++应用程序。)尽管Java应用程序在显示本机方面做得很好,但是某些区域仍然缺少用户注意到差异。 潜在的问题是Java应用程序不能真正地显示为本机,因为本机应用程序具有不公平的优势:可以为该OS专门编写它们,从而使它们可以利用独特的本机OS功能。 Java代码受到其“在任何地方运行”的口号的限制,并且通过Java本机接口(JNI)调用本机函数是很大的禁忌。
到目前为止,Java开发人员愿意忍受这种不足,以换取编写可在任何OS上运行的软件的优势。 但是随着Java SE 5的发布,特别是Sun推动Java桌面重新焕发活力的努力,一些开发人员希望最终消除Java应用程序与本机应用程序之间的区别。 创建JDIC项目就是为了弥合这一差距(请参阅参考资料 )。 正如JDIC网站所声称的那样,JDIC“旨在使基于Java技术的应用程序('Java应用程序')成为当前桌面平台的头等公民,而又不会牺牲平台的独立性。”
本文向您介绍了JDIC项目,以及它如何努力使Java客户端应用程序看起来更加本地化。 通过一系列示例,您将了解JDIC中当前存在的组件以及“孵化器”中的某些组件(正在进行中)。 我们将讨论JDIC提供的几乎所有内容,理想情况下会激发您的兴趣,以将其包含在您的应用程序中,甚至帮助您说服您为项目本身做出贡献。
关于JDIC的一个重要说明:这仍然是一个beta项目,意味着任何JDK版本都不支持它,并且随时可能更改。 因此,您必须在基于JDIC的应用程序中附带必需的文件,因为没有Java虚拟机(JVM)将支持它。 并且由于该API可能会因发行版本而异,因此本文中的函数名称在某些时候可能会有所不同。
包好了
JDIC项目有两个目标:保持Java API跨平台,以使程序可以在任何计算机上运行并支持人们使用的每个OS。 因为新功能要求在每个OS上调用本机函数,所以这似乎是一个困难的位置。JDIC通过使用其Java API作为所有这些本机调用的包装来实现此目的。 JDIC组件代码本身会找出正在运行应用程序的操作系统,并调用适当的JNI函数。 (您可以仅描绘每个操作系统代码中的if / else链。啊,跨平台兼容性的代价。)图1说明了JDIC如何包装本机调用:
图1. JDIC如何包装本地调用

设置它们
设置机器以编写和运行使用JDIC的应用程序比通常要复杂一些。 除了通常的类路径要求之外,您还必须提供Java类将调用的OS库。 每个操作系统都有一个不同的操作系统库,因此,如果要使用JDIC将应用程序移植到许多不同的操作系统,则必须为每个操作系统提供一个库。 从本文所基于的JDIC版本0.9开始,JDIC可与Windows,Linux和Solaris系统一起使用(对不起,Macintosh风扇)。
首先下载跨平台的JDIC软件包,其中包括:
- jdic.jar :此JAR文件包含任何JDIC开发所需的所有Java类。 它必须在您的类路径中才能进行编译。
- jdic.dll和tray.dll :在Windows安装中,这两个文件都需要进入C:\ Windows目录(或等效目录)。 这些包含jdic.jar Java方法和本机OS方法之间的“桥梁”方法。
- libjdic.so和libtray.so :在Solaris和Linux系统上,这两个文件都必须放入LD_LIBRARY_PATH文件夹中。
设置这些文件应该可以使您正常运行。 如果不是,请阅读JDIC下载的README文件中的文档以检查任何特定的OS需求。 一切准备就绪并准备就绪后,请继续阅读以开始使用示例。
填补差距
我将为每个JDIC组件展示一个小的示例应用程序,每个应用程序都解决了Java语言中存在的特定空白。
WebBrowser
组件
JDIC项目中的第一个组件(以及该项目的最初灵感)是WebBrowser
,它使您可以利用OS的内置浏览器。 熟悉Swing的人都非常了解,很难在Java应用程序中查看Web页面。 现有的Swing组件(例如JEditorPane
在显示除最简单的Web页面以外的所有页面方面做得很差。 如果涉及到任何DHTML脚本,那就不用管它了-现有的Swing组件无法显示它。 这使得Swing开发人员无法选择在应用程序中显示HTML页面-鉴于Web在任何桌面应用程序中(对于帮助页面和自述文件)是如此重要,因此这是一个严重的障碍。
对于Swing开发人员而言,尤其令人沮丧的是,现在每台机器上都可以使用功能齐全的浏览器,但仍无法对其应用程序使用。 内置浏览器(Windows中的Internet Explorer或Linux计算机上的Mozilla)甚至被其他本机应用程序使用。 Swing功能上的巨大差距以及对解决方案的轻松访问使WebBrowser
成为JDIC项目的良好起点。
WebBrowser
类允许Swing应用程序将本机浏览器嵌入到任何应用程序中。 不过,请务必注意, WebBrowser
只是 Web浏览器应用程序的呈现部分。 该组件不包括“ 后退”按钮,地址栏,状态栏或不属于应用程序呈现部分的任何其他内容。 但是,正如您稍后所看到的, WebBrowser
确实包含一些使您实现这些通用浏览器功能的方法。
WebBrowser组件继承自java.awt.Canvas class
,这意味着它是一个Abstract Windowing Toolkit(AWT)组件。 这应该引起Swing开发人员的关注,他们熟悉混合AWT和Swing组件的问题,包括重新绘制问题。 WebBrowser
组件重写java.awt.Canvas.paint()
方法以将HTML直接呈现在Canvas本身上,从而保持最佳性能。 这对Swing开发人员意味着什么? 这意味着您必须在JPanel
包含WebBrowser
才能在Swing中使用它。 这并不像听起来那样糟糕。 JPanel
是包含WebBrowser
的逻辑组件,其他Swing组件已经具有内置HTML支持。
但是,当您可以观看视觉组件时,为什么还要继续谈论它们呢? 要运行的示例是JDIC下载附带的示例,并与本文的其余示例重新打包在一起,因此您可以一次下载所有示例(请参阅下载 )。 要查看实际的WebBrowser
示例,请运行demo.Browser.Browser
主类。 图2显示了运行中的WebBrowser示例:
图2.运行中的WebBrowser
既然您已经看到了WebBrowser
的实际功能,请看一下WebBrowser
类中的一些方法,这些方法使您可以创建功能齐全的浏览器:
- 每个浏览器的四个预期功能:
-
back()
-
forward()
-
refresh()
-
stop()
-
- 让应用程序更改URL的方法:
-
getURL()
-
setURL()
-
- 使应用程序直接通过HTML传递的方法:
-
getContent()
-
setContent()
-
- 让应用程序侦听
WebBrowserEvent
的方法,本节稍后将对此进行解释:-
addWebBrowserListener()
-
removeWebBrowserListener()
-
- 最新的方法:
-
executeScript()
-
executeScript()
方法使程序可以使用JavaScript执行scriptlet,并在加载的Web页面或HTML内容上执行脚本。 该功能很酷,因为您可以使用它来更改网站(甚至是第三方网站)的外观。 尝试在页面加载后将以下行添加到演示应用程序:
webBrowser.executeScript("document.bgColor='blue';");
这使每个网站都加载了蓝色背景,从而覆盖了网站的默认背景色。
WebBrowserEvent
/ WebBrowserListener
框架的工作方式与Swing中的每个事件/侦听器框架完全相同,但是在这种情况下,涉及WebBrowser
可以触发的所有与WebBrowser
相关的动作。 对WebBrowser
触发的事件感兴趣的类应通过其addWebBrowserListener()
方法将自己添加为WebBrowser
侦听器。
WebBrowserListener
接口中必须实现的方法是:
- documentCompleted() :完成文档加载时调用。
- downloadComputed() :下载操作完成,暂停或失败时调用。
- downloadError() :在下载操作期间发生错误时调用。
- downloadProgress() :更新下载操作的进度时调用。
- downloadStarted() :开始下载操作时调用。
- statusTextChange() :更改状态栏文本时调用。
- titleChange() :更改文档标题时调用。
简而言之,就是WebBrowser
组件。 WebBrowser
类和WebBrowser
事件/侦听器框架中的所有方法使您可以创建一个完整且功能强大的Web浏览器应用程序。 它可能不完全可以与Internet Explorer或Firefox匹敌,但Swing开发人员不再因该库对网页和HTML的支持不佳而受阻。 您可以放心地在所有应用程序中获得全面的Web支持,甚至用于显示最困难的网站。 作为JDIC项目的灵感来源, WebBrowser
开始朝着正确的方向滚动。
SystemTray
组件
SystemTray
组件是JDIC中最SystemTray
组件之一。 它使Java应用程序可以将图标放置在系统托盘中(在Windows中,屏幕右下角的区域包含诸如音量图标之类的图标)。 Windows应用程序中日益增长的趋势是向系统托盘图标添加大量功能。 即时消息应用程序就是一个很好的例子。 它们通常仅通过系统托盘图标为用户提供许多选择的权限,例如关闭应用程序。 到目前为止,Java应用程序还无法参与这一趋势。
像JDIC中的大多数项目一样,此组件的API简单易用。 实际上,整个org.jdesktop.jdic.tray
包只有两个类: SystemTray
和TrayIcon
,它们抽象化系统托盘本身,而TrayIcon
提取系统托盘中的各个图标。
运行示例应用程序( demo.jdic.TrayDemoFrame
类),以查看应用程序如何使用JDIC的系统托盘功能(请参阅下载 )。 运行该应用程序时,您应该在Windows系统托盘中看到yin-yang图标,如图3左上角的图标。 (它在Linux和Solaris中的外观当然会有所不同。即使在Windows中,它的外观也不会与图3完全相同,因为不可能从系统托盘中截取菜单的屏幕截图,因此这是一个-创建的图像。)
图3.运行中的SystemTray
该示例中有趣的部分不是JFrame
本身,而是它如何处理与系统托盘的交互。 看一下示例应用程序中设置此代码的代码。 第一步是获取机器系统托盘的实例:
SystemTray tray = SystemTray.getDefaultSystemTray();
接下来的几个步骤将创建任务栏图标:
final TrayIcon trayIcon = new TrayIcon(getTrayIcon(), "Tray Demo", getPopupMenu());
trayIcon.setIconAutoSize(true);
trayIcon.addActionListener(new ActionListener()
{
public void actionPerformed(ActionEvent e)
{
setVisible(true);
}
});
TrayIcon
类(不幸的是)目前正在对它与鼠标单击的交互方式进行硬编码。 (JDIC用户强烈要求对此进行更改。) TrayIcon
在单击鼠标左键时会触发一个ActionEvent
,并在单击鼠标右键时会显示弹出菜单。
最后,将新的TrayIcon
添加到系统托盘:
tray.addTrayIcon(trayIcon);
就这样-您已经创建了一个漂亮的系统托盘图标,该图标为Java应用程序提供了非常原生的感觉。
JDIC项目最近向TrayIcon
类添加了displayMessage()
函数。 它使TrayIcon
可以显示Windows用户熟悉的“气泡消息”。 通过单击示例应用程序中的“ 警报”按钮,您可以看到此气泡消息的运行情况。 这是实现它的代码:
getBtnAlert().addActionListener(new ActionListener()
{
public void actionPerformed(ActionEvent e)
{
trayIcon.displayMessage("Alert", "This is an Alert Message", TrayIcon.INFO_MESSAGE_TYPE);
}
});
本机文件支持
当前,Java应用程序无法使用默认应用程序打开文件。 例如,Java应用程序无法在Microsoft Word中打开.doc文件。 它不知道每台计算机上Word的路径,最重要的是,它无法知道Microsoft Word是否是使用.doc文件的首选应用程序。 而且没有简单的方法可以从Java应用程序中打印此.doc文件。
JDIC中的Desktop
类通过创建一些简单的静态方法来解决这些问题,这些方法使Java应用程序与系统应用程序进行交互。 这些系统应用程序内置在OS中-只有OS知道哪个应用程序应打开.doc文件。
该组件总体上不如SystemTray
组件有用,但确实可以满足需求。 任何处理各种文件类型的Java应用程序(例如文件浏览器)都可以使用Desktop
类的方法:
- Desktop.browse(URL url) :在系统浏览器中打开一个网站。
- Desktop.edit(File f) :使用与文件类型的edit命令关联的程序来打开文件。
- Desktop.open(File f) :使用与文件类型的open命令关联的程序来打开文件。
- Desktop.print(File f) :打印文件。
- Desktop.mail(Message m) :自动打开系统的首选电子邮件程序,并填充了某些字段。
您可以在示例程序demo.jdic.FileExtensionDemo
看到正在使用的功能。 该应用程序的顶部让您浏览文件,然后打开它,如图4所示:
图4.本机文件支持
当您单击“ 打开”按钮时, Desktop
类将调用系统的默认PDF查看器,如以下代码所示:
else if (e.getSource() == getOpenButton())
{
try
{
Desktop.open(new File(getTxtFile().getText()));
}
catch (DesktopException ex)
{
ex.printStackTrace();
}
}
FileTypes
组件
目前,JDIC项目的最后一块是FileTypes
。 乍看起来,该组件似乎并不重要,但是在我对其进行了描述之后,您会发现它是创建整个Java桌面应用程序的重要组成部分。 FileType
解决的根本问题是现有Java程序无法注册文件扩展名并将其与应用程序关联。 当您双击带有.doc扩展名的文件时,Windows会自动知道在Word中打开该文件。 Java应用程序无法做到这一点。 双击带有新扩展名的文件时,您将无法编写自动打开的Java应用程序。 您无法注册文件扩展名(例如“ jexx”)来打开自己的Java应用程序。 这对Java应用程序开发人员来说是一个严重的挫折,因为它使他们的应用程序无法像本机操作系统的一部分。 告诉我-当用户双击文件时,是否要他们导航“打开方式...”对话框,还是希望该应用程序简单地打开?
org.jdesktop.jdic.filetypes
包中的三个类通过允许Java应用程序注册文件扩展名并将它们与打开,编辑和打印操作相关联来填补这一空白。 您可以选择让不同的应用程序进行打开和编辑。 例如,您的应用程序可以使用浏览器打开XML文件,然后使用文本编辑器进行编辑。 将操作链接到关联后,可以在操作系统中注册它。
开始研究demo.jdic.FileExtensionDemo
类(与上一节中讨论的示例应用程序相同,本机文件支持 )。 这次,您将使用对话框的下半部分创建FileType
。 图5显示了填充字段后的示例外观:
图5. FileTypes演示
单击“ 注册”按钮后,可以在“ Windows文件夹选项”对话框中打开“文件类型”选项卡,然后查看刚刚创建的内容,如图6所示:
图6.协会注册
现在看一下示例应用程序相关部分的代码:
else if (e.getSource() == getRegisterButton())
{
String verb = getTxtVerb().getText();
String command = getTxtCommand().getText();
String fileExt = getTxtExt().getText();
// Create the Action object that will store the
// verb (in this example "open" with the command "in this case the
// link to the java.exe
Action action = new Action(verb, command);
// Next we need to create the Association which we'll use to
// register in the operating system
// You can link the action we just created to the
// association and a corresponding file extension.
Association association = new Association();
association.addAction(action);
association.addFileExtension(fileExt);
// Finally, after we have created our Association, we use the
// AssociationService, which will talk directly to the operating system to
// register the file type
AssociationService associationService = new AssociationService();
try
{
associationService.registerSystemAssociation(association);
}
catch (RegisterFailedException ex)
{
ex.printStackTrace();
}
catch (AssociationAlreadyRegisteredException ex)
{
ex.printStackTrace();
}
}
示例显示了它是多么简单的创建,并在操作系统注册的文件类型的兴趣还有一些其它方法Association
类可以提高文件类型:
- setIconFileName() :让应用程序在文件类型上设置图标。
- setMimeType() :允许应用程序在文件类型上设置Mime类型。
最后一步,要一起展示本机文件支持和FileTypes
的功能,请在桌面上创建一个名为example.jexx的文件,如图7所示:
图7.桌面文件
现在,无需双击example.jexx文件(不会证明任何内容),而可以使用您在本机文件支持中了解的JDIC代码通过FileExtensionDemo
应用程序将其打开。
图8. FileType和本机文件支持演示

单击“ 打开”按钮时,您将看到此文件启动记事本。 本机文件支持和FileType
组件的结合是Java应用程序开发人员工具箱的关键添加。 可执行JAR文件随附了对Java应用程序的本机支持的双击支持。 现在,用户最终可以通过双击应用程序的关联文件来打开您的Java应用程序。 这一小而独特的功能使Java应用程序看起来像OS的根深蒂固。
在孵化器中
到目前为止,我概述的组件已经完成,并且是JDIC项目的功能部分。 JDIC还包括一组正在建设中的组件,称为孵化器项目(又称沙箱)。 在孵化器项目中,您会发现很多程度的完整性,从已完成并等待进入JDIC程序包的组件到仍然只是纸上想法的组件。
作为一个公开项目的一部分,该项目对任何愿意贡献的人的想法和辛勤工作开放,孵化器提供了测试新想法的机会。 只有经过测试并且其API和功能获得批准的组件才会升级为分布式JDIC包。 在阅读本节中的孵化器组件时,请记住这一点-非常酷,但是不完整。 他们可能需要几个月才能准备好黄金时间。
IconService
IconService
类执行将图标名称(通常以难以理解的形式,例如C:\ Program Files \ IBM \ eclipse.exe,1出现)转换为java.awt.Image
对象的单一任务。 一旦获得Image
对象,就可以对其进行操作-这样您就可以操作图标本身。 通过调用getIconFileName()
方法从另一个JDIC类( Association
类)获得图标名称。 这是将图标转换为Image
对象的方法:
Image i = IconService.getIcon(Association.getIconFileName(), 1);
系统信息
SystemInfo
类尝试提供有关操作系统本身的信息。 这包括诸如系统空闲时间以及用户会话是否被锁定之类的项目。 不过,在撰写本文时,仅此而已,并且不存在浏览或阅读方法的API。 该课程似乎仍处于真正的起步阶段,请继续关注是否正在进行更新。
浮船坞
FloatingDock
类旨在模仿Windows任务栏,既允许将组件添加到该任务栏,又可以将其自身停靠在屏幕的某个区域。 FloatingDock
基本上是一个绑定到某个区域(左,右,下或上)的JPanel
。 在大多数情况下,它包含与JPanel
相同的功能,可让您更改布局以及添加和删除组件。 FloatingDock
还允许应用程序随时更改区域,就像将Windows任务栏拖动到屏幕上的新位置一样。
不要误以为FloatingDock
提供与任务栏完全相同的功能。 它仅启用停靠到屏幕区域的功能。 如果您想模仿任务栏, JToggleButton
您决定是否要添加用于显示JToggleButton
,调整其大小等功能。
这是在屏幕底部创建FloatingDock
对象并向其添加JButton
方法:
FloatingDock dock = new FloatingDock();
dock.setLocation(FloatingDock.BOTTOM);
dock.add(new JButton("Window 1"));
杂项包
Misc
培养箱软件包包含折衷的单项任务组件集合。 这些组件仅包含一个或两个静态方法,这些方法试图填补Java到本机转换中的一个简单空白。 在撰写本文时,此软件包中的类仅支持Macintosh,因为开发人员认为Mac没有获得应有的重视。 此时,没有什么可部署的,因为该项目尚未为Mac进行构建。 因此,就目前而言,您必须对这些方法及其所能做的事情感到满意,然后交叉指责,希望在不久的将来发布该版本。
卷
Volume
类是Misc
程序包的成员,它控制计算机上的音量级别。 public float Volume.getInstance().getVolume()
获取当前音量,而public void Volume.getInstance().setVolume(float vol)
设置音量。
此类还允许用户通过提供addPropertyChangeListener()
函数来注册卷中的更改,该函数在计算机上卷更改时通知感兴趣的类(但不一定通过Volume
类本身)。
墙纸
Misc
程序包的另一个成员, Wallpaper
类及其对应的WallpaperFactory
类,使Java应用程序可以在OS上更改墙纸(桌面上显示在后台的图像)。 这是更改墙纸的一些示例代码:
Wallpaper wall = WallpaperFactory.createWallpaper();
wall.setBackground(new File("/background.jpg"), Wallpaper.CENTER);
警报器
Alerter
类是Misc
程序包的另一个成员,它通过让未关注的应用程序(即,位于其他窗口后面)通知用户需要采取某些措施,从而解决了很小的Alerter
。 在Mac(目前支持该类)上,此警报会“弹起”停靠栏图标。 在Windows上,当它被支持时,它将闪烁任务栏图标,直到选中它为止。 这是一个代码示例:
Alerter.newInstance().alert();
码头菜单
Misc
包中的最后一个类用于Dock菜单,Dock菜单仅在Mac中存在,而在Windows或Linux系统中没有并行组件。 DockMenu
类使用户可以将菜单附加到Mac应用程序中的Dock Menu中。这是如何使用DockMenu
类的示例:
JMenu menu = new JMenu("Exit");
DockMenu.newInstance().setMenu(menu);
FileUtil
JDIC孵化器的最新添加是FileUtil
,该类提供了一些新功能来补充JDK中的java.io.File
类。 public java.math.BigInteger getFreeSpace(File dir)
方法返回public java.math.BigInteger getFreeSpace(File dir)
的可用空间,而public boolean recycle(File f)
将文件放入操作系统的回收站,而不是简单地将其删除。
愿望清单
JDIC及其孵化器中的组件列表非常详尽,但绝不能消除Java应用程序与本机应用程序之间的所有空白。 本节是我和许多其他开发人员希望看到的在JDIC中实现的组件的愿望清单。 对于那些野心勃勃的读者,请记住,JDIC是一个开放项目,任何人都可以随时做出贡献-因此,随时随地接受这些想法并与他们一起运行。
本地支持的非矩形窗口
非矩形框架在应用程序中变得非常流行(例如,Microsoft Media Player)。 多年来,Swing开发人员一直在呼吁支持跨多个操作系统的非矩形窗口。 如果开发人员曾经在JDIC中添加对此的支持,则整个Swing社区都会立即将他们拱顶到极客的万神殿。 (一个解决方案,现有的尝试包括从L2FProd.com项目仅用于Windows的解决方案和我自己的IFrame,这是一个“几乎没有”的解决方案;见相关主题 。)
桌面“新”支持
当用户右键单击Windows桌面时,他们会看到“ 新建”菜单选项,其中包含一个子菜单,该子菜单包含用户可以创建的常见文件类型。 此时,Java语言无法访问此菜单。
特定于文件的右键单击支持
在Windows中右键单击文件的用户将看到该文件的选择。 某些应用程序始终自动将其默认行为更改为这些选择列表。 (例如,如果右键单击任何文件类型,请注意如何选择WinZip(例如,如果已将WinZip安装在计算机上)。)Java语言无法将程序或选择永久添加到此菜单中。
SystemInfo类中的其他功能
SystemInfo
类中的其他功能将很有用,包括支持查找进程名称和编号,网络状态,网络连接速度和电池寿命。
用户和组管理
如果Java应用程序可以管理OS的用户和访问组,包括处理密码管理,那就太好了。
时间和日期
让Java程序更改OS上的时间,日历和时区如何?
结论
JDIC项目填补了Swing和Java编程语言中普遍存在的主要空白。 随着其他人的不断努力,它将进一步缩小差距,有朝一日,用户将无法分辨Java应用程序与本机应用程序之间的区别。
如您所见,JDIC(在撰写本文时)包括成熟的,可立即生产的项目和孵化器,其中包含处于不同开发阶段的项目。 孵化器提供了一些有趣的项目,这些项目可能会在不久的将来实现。 如果您决定冒险并在您的应用程序中包含一个孵化器项目,则要记住的重要一点是,该项目可能随时发生变化,可能有错误,甚至根本无法工作。
如果您喜欢本文中看到的内容,我最好的建议就是参与JDIC项目。 该项目对任何有兴趣参与的人开放,并且像大多数开源项目一样,它只能做人们愿意贡献的事情(请参阅参考资料 ,获得指向您可以注册以参与的站点的直接链接)。 )。 无论您是要帮助完成孵化器中的某些项目,还是要遵循我的愿望清单中的想法,还是想实现自己的想法,开发社区都会非常感谢您的帮助。 不要以为您需要成为本机代码或JNI的专家,也不必知道每个操作系统。 孵化器项目使您可以散布自己的想法,并从其他志愿者那里获得反馈和帮助。
翻译自: https://www.ibm.com/developerworks/java/library/j-jdic/index.html