SWT Browser 渲染 HTML 页面内容若干问题的解决方案

红薯 发布于 2010/06/19 16:18
阅读 3K+
收藏 1
SWT

简介: 本文介绍了 SWT Browser 渲染定制的 HTML 页面内容中一些常见问题(主要是国际化问题、Accessibility 问题 和平台相关问题)的解决方案。接下来,本文将详细的讲解问题的由来并提供解决方案。 这些方案并不局限于本文的应用,它们具有一定的通用价值。Eclipse 插件和 RCP 应用的开发人员都可以从文章中获益。

SWT Browser 是 Eclipse SWT 的标准部件,该部件植入了平台流行的 HTML 渲染引擎:在 Microsoft Windows 平台上是 IE,在 Linux 平台上是 Mozilla,在 Apple Mac 平台上是 Safari。它提供了把 HTML 整合到 Java 平台的能力。

在产品级别的软件中使用 SWT Browser 来渲染定制的 HTML 内容,需要考虑更多的问题。首先是国际化问题,针对不同国家的语言包(Language package),部件渲染相应的 HTML 内容。其次是 Accessibility 问题。Accessibility,经常被缩写为 a11y,指的是软件产品的可访问性、易用性,特别是指对于诸如视力低下等残障人士的使用上的无障碍性。很多国家的法律条文规定,软件产品需要满足可访问 性的要求。比如美国、欧洲、日本等国家都针对 a11y 立法,不符合 a11y 的软件程序很多都不在政府机关等的采购范围内。在本文中我们着重介绍 HTML 内容如何响应操作系统字体大小调整的这一可访问性问题。 Java 本身是夸平台的,在解决国际化和 Accessibility 两个问题的同时会涉及一些平台相关的问题,我们也需要技巧来解决。接下来,我们将详细的加以介绍,以飨读者。

文章的组织结构如下:

  • 国际化问题及其解决方案
  • Accessibility 问题及其解决方案
  • 平台相关问题
  • 小结

国际化问题及其解决方案

国际化是创建适合于国际市场的软件的过程。除了经济利益之外,某些国家或地区要求产品在进入其市场之前通过政府设置的某些本地化要求。(国际 化 Eclipse 平台的过程分两步完成: 1)启用产品的本地语言支持(National Language Support (NLS))确保了产品是为本地语言功能设计的,并且产品使用适当的 API 来处理本地语言数据。2)将本国语言元素翻译成外语。 更详细的介绍请参考文献 [3]) 在本文中,我们的国际化问题是指如何完成对 SWT Browser 所渲染的 HTML 内容的多国语言翻译的支持。

SWT Browser 部件提供了两种渲染 Web 页面的方法:setUrl 方法和 setText 方法,如清单 1 所示。setUrl 方法非常简单,只要传入 URL 地址参数,Browser 就会渲染对应的 HTML 页面内容。对于 setText 方法,我们需要把 HTML 文本字符串内容作为参数传入,进而渲染 HTML 文本内容。

清单 1. Browser 渲染 HTML

				
/*
* Browser example snippet: render HTML that includes relative links from memory
* For a list of all SWT example snippets see
* http://www.eclipse.org/swt/snippets/
* @since 3.0
*/
public class Snippet137 {
public static void main(String [] args) {
/* Relative links: use the HTML base tag */
String html = "<html><head>"+
"<base href=\"http://www.eclipse.org/swt/\" >"+
"<title>HTML Test</title></head>"+
"<body><a href=\"faq.php\">local link</a></body></html>";
Display display = new Display();
Shell shell = new Shell(display);
shell.setLayout(new FillLayout());
Browser browser;
try {
browser = new Browser(shell, SWT.NONE);
} catch (SWTError e) {
System.out.println("Could not instantiate Browser: " + e.getMessage());
display.dispose();
return;
}
browser.setText(html);
browser.setUrl(“http://www.eclipse.org/swt”);
shell.open();
while (!shell.isDisposed()) {
if (!display.readAndDispatch())
display.sleep();
}
display.dispose();
}
}

在处理国际化多语言翻译这个问题上,如果采用 setUrl 方法渲染方法则需要为每一种语言提供一个 HTML 页面。那么程序的可维护性和灵活性就非常差,如果页面需要很小的变动,这些 HTML 页面都需要相应的更改。如果动态的生成 HTML 页面内容,应用 setText 渲染就解决了这个问题了。我们可把 HTML 页面内容分成几个部分:1)不需要国际化的模版部分(文档表示格式,即 HTML tags) 2)需要动态生成文本内容的部分 ( 比如 .css 文件的路径 ) 3)需要国际化的内容部分。

也就是说,本文的国际化解决方案是:使得 HTML 页面表示和需要国际化的内容相分离。我们把 HTML Tags 等抽取成模版,这部分是通用的。可以基于 Eclipse 平台国际化的技术来国际化 HTML 页面中的相应内容。简单易行,方便又快捷。同时也提高了程序架构的可维护性,可扩展性和灵活性,也为解决下文的 Accessibility 问题、平台问题打好了基础。

定制 HTML 页面表示模版

清单 2. 表示模版

				
<html>
<head>
<meta http-equiv="Content-Type" content="text/html;">
<title>$$PageTitle$$</title>
<style type ="text/css">
</style>
<link href="@PATH_INDEX@mm1.css" rel="stylesheet" type="text/css">
<link href="@PATH_INDEX_CSS@fontsize.css" rel="stylesheet" type="text/css">
<!-- <SCRIPT type="text/javascript" src="@PATH_INDEX@demo.js"> -->
<SCRIPT type="text/javascript"> … </SCRIPT>
</head>
<body>
<DIV ID="Main">
<DIV ID="banner">
<DIV ID="homedemoicon"><img src="@PATH_INDEX@home_demoicon.gif" alt=""></DIV>
<DIV ID="HomeDEMO"><img src="@PATH_INDEX@home_demo.gif" alt=""></DIV>
<DIV ID="homedemomark">&nbsp;</DIV>
<DIV ID="hdnew"><img src="@PATH_INDEX@home_demo-new.gif" alt="$$Demo$$"></DIV>
<DIV><H1 class="startedHead">$$PageHeader$$</h1></DIV>
</DIV>

</DIV>
</body>
</html>

清单 2 中 给出了模版的一个示例。 在实例中,$$ PageTitle$$ 用以标志需要国际化的内容, PageTitle 是国际化文件(demo_en.properties)中 key 值。我们将在程序中处理 $$ ×× $$ 等标志,从而动态的加入国际化好了的 HTML 页面内容。

读者会看到 @PATH_INDEX@ 标记, 它是用来标记资源的路径信息。在程序中,将会动态生成资源的绝对路径信息。否则,HTML 页面中的图片,CSS 等不会被加载进来。(这些标记信息并不是绝对的,开发者可以设定自己的标记信息。)

国际化 HTML 页面的内容

把需要国际化的内容抽取到一个文件里(demo_en.properties)。 如清单 3 所示:

清单 3. 国际化 HTML 页面内容文件

				
# NLS_ENCODING=UTF-8
# NLS_MESSAGEFORMAT_ALL
## G11N GA UI
PageTitle=Demo Title

PageHeader=Demo Header

Demo=More Information

读者会发现这和普通的 Eclipse 平台国际化技术没有任何差别,这正是这种解决方案的目的所在。在程序中,我们使用 java 正则表达式把模版中的内容标志,路径信息标志替换成国际化好了的 HTML 页面内容信息和文件的绝对路径信息。这样 SWT Browser 的实例,通过调用 setText 方法就可以渲染正确的 HTML 页面信息了。

一些常见问题的解决技巧

1 获取文件的绝对路径信息

如何在程序中根据 Browser 实例所在的 eclipse 插件信息获取当前产品的绝对路径信息呢?程序需要把 HTML 表示模版中的绝对路径标志替换成绝对路径的信息。如清单 4 所示:

清单 4. 获取文件的绝对路径信息

				
String absolutePath = null;
try {
absolutePath = FileLocator.toFileURL(
DemoPlugin.getDefault().getBundle().getEntry(
"/")).toExternalForm();
} catch (IOException e) {
e.printStackTrace();
}

2$符号问题

如果文件的路径信息里包含 $ 符号,那么在应用正则表达式进行替换的时候就会有异常抛出来。所以一定要对文件路径信息进行预处理。如清单 5 所示:

清单 5. 处理文件路径信息中的 $ 符号

				
/*
* '<','>','?',':','|','*','\','/' 等符号在 Windows 操作系统中是不允许出现在文件路径中的。
* 只有 $ 符 * 号需要处理。
*/
private void transDollar(String filepath) {
Pattern pattern = Pattern.compile("\\$"); //$NON-NLS-1$
Matcher mT = pattern.matcher(filepath);
_absolutePath = mT.replaceAll("\\\\\\$"); //$NON-NLS-1$
}

3BIDI问 题

bidi 问题是软件产品中的一个常见问题(阿拉伯文字是从右向左读的)。在我们的解决方案中,为 bidi 提供了专门的 HTML 表示模版, 模版文件放置到不同的文件目录中。所以在 bidi 模式下,文件的路径信息也不同。在程序中要对 bidi 问题进行处理, 如清单 6 所示:


清单 6. 处理 BIDI 问题

				
BrowserContentGenerator gen = new BrowserContentGenerator();
/*
* Check BIDI condition
*/
int style=DemoPlugin.getDefault().getWorkbench().
getActiveWorkbenchWindow().getShell().getStyle();
if((style & SWT.RIGHT_TO_LEFT) != 0){
// directory configuration
gen.setDIR(BrowserConstant.DIR_RTL);
// template file configuration
gen.setTMPFILE(BrowserConstant.TMPFILE_RTL);
}

Accessibility 问题及其解决方案

我们在简介部分已经介绍了 Accessibility 的概念。一般而言呢,对于残障人士,尤其是视力不好的用户,大的字体,间隔分明的布局体系有利于他们阅读软件产品中的文字内容。在 RCP 或基于 Eclipse 插件技术的应用程序中,根据 Accessibility 的要求,程序的字体要响应操作系统字体大小的变化。

读者可能会想,这不是很简单的一件事情嘛。比如我在 Windows 平台上,打开 IE 浏览器就可以更改当前 Web 页面的大小设置。熟悉快捷键的高手更是说 ctrl 键加上“+”或“-” 不久搞掂了嘛?问题是我们使用的是 SWT 的 Browser 部件。我们可以如上面所说的在 Windows 平台去改变 IE 浏览器字体的设置,然后重新启动程序,这样才能生效。不过,还有一个前提条件,在我们定制的 HTML 页面中不应该有对 fontsize 的绝对设定。

我们可不可以应用 CSS 文件动态的调整 HTML 内容大小的显示呢?也就是说,程序要监听到操作系统字体大小变化的事件,并做相应的处理。答案是肯定的。下面我们主要介绍这种解决方案。

第一步,SWT 程序要监听到操作系统字体变化的事件。

清单 7. SWT 响应操作系统事件

				
Display display = PlatformUI.getWorkbench().getDisplay();
systemFont = display.getSystemFont();// 开关变量
osListener = new Listener() {
public void handleEvent(Event event) {
Font currentSystemFont = display.getSystemFont();
if (!currentSystemFont.equals(systemFont)) {// 字体发生变化
systemFont = currentSystemFont; // 缓存当前操作系统的字体
// 使用相应的 CSS 文件动态的生成 HTML 内容
}
}
};
display.addListener(SWT.Settings, osListener);

清单 7 中,给出了在 SWT 程序中响应操作系统事件变化的代码片段(SWT 的事件类型是 SWT.Settings)。

第二步,获取操作系统字体的显示状态。

接下来,我们应该获取操作系统当前字体显示的状态。在 Windows 操作系统上如何改变字体显示的大小呢?点击 桌面-> 属性-> 外观-> 字体大小,如图 1 所示。我们会发现 Windows XP 操作系统字体大小的显示有正常,大字体,超大字体三个选项。在 SWT 程序中,我们拿到的是字体的大小,而不是字体的这三个状态。我们的应用程序是要根据三个状态来应用三个不同的 CSS 来动态的生成 HTML 文本内容。这就需要读者对 Windows 操作系统的字体有深刻的了解。在 Windows XP 操作系统上,系统默认的字体大小是 8 或则 9。 这个默认值取决于操作系统的语言版本。中文,韩文,日文等东方文字的默认字体大小是 9 ,而西方文字默认字体大小是 8。在 Windows vista 以及 Windows 7 等操作系统中,是应用不同的主题(theme)来设定的操作系统字体大小的,其 Segoe UI 默认字体大小是 9。

图 1. 获取操作系统字体状态
图 1. 获取操作系统字体状态

清单 8. 获取操作系统字体状态

				
private static final int SMALL_FONT = 9; //$NON-NLS-1$
private static final int MIDDLE_FONT = 11; //$NON-NLS-1$
/*
* Get current OS font size
* @return font size of OS
*/
private int getSystemFontSize(){
final Display display = PlatformUI.getWorkbench().getDisplay();
Font osFont = display.getSystemFont();
FontData[] fds = osFont.getFontData();
int fontSize = fds[0].getHeight();
return fontSize;
}
/**
* Get actual FontSize object
* @param newValue, preference stored value
*/
public FontSize getFontSize(String newValue){
int osFontSize = getSystemFontSize();
if(fontSize<=SMALL_FONT){
return FontSize.NORMAL;
}else if(fontSize<= MIDDLE_FONT){
return FontSize.MIDDLE;
}else{
return FontSize.LARGE;
}
}

从清单 8 中可以看到,如果操作系统当前的字体是 9 或者小于 9,SWT 应用程序会应用字体小的 CSS 文件渲染 HTML 文本内容。当字体小于等于 11 而大于 9,则用字体是中号的 CSS,否则应用大字体的 CSS 渲染 HTML 文本内容。 读者可能会问了,这个字体大小 11 是怎么算出来的?在 Windows 平台中,如上图 1 所示,如果选择了大字体,那么字体会比正常状态的增大 125 %;如果选择了特大字体,那么字体会增大 150 %。

某些弱视的群体,可能是色盲患者,经常需要调整操作系统的颜色设置来达到高对比度的效果。我们可以在程序中判断当前是否是高对比度的模式 (boolean isHighContrast = getDisplay().getHighContrast();) 然后应用不同的 CSS 文件,处理诸如 Web 页面里的图片等相关的 accessibility 问题,本文略之。

平台相关问题

在苹果 Mac 平台上,默认没有改变系统缺省字体的功能(当然读者可以下载工具来实现之)。 按照 Accessibility 的要求,(如果要求不是非常严格的话,程序在一种平台上实现 Accessibility 即可),可以不用考虑软件在 Mac 平台上的可访问性要求。 在程序中可以使用 _isMac = SWT.getPlatform().equals("carbon") 来判断当前是否是 Mac 平台。同理在 linux 平台上是 _isGtk = SWT.getPlatform().equals("gtk")。

可以根据不同平台的特点,使用不同的模版及 CSS 文件动态生成 HTML 内容显示。

小结

本文并没有详细介绍 SWT Brower 部件应用的 APIs,读者可以访问 SWT Snippet的网站获得更多这方面的知 识。 在产品级的 Eclipse 平台应用程序中使用 SWT Brower 渲染 Web 页面时,国际化问题,Accessibility 问题,平台相关的一些问题,是开发人员必须处理的。 本文则给出了很好的解决方案。关注这些问题的 Eclipse 插件项目和 RCP 程序的开发人员,都可以从文中获益。

加载中
返回顶部
顶部