在许多平台中,Browser
控件皆被作为一个必需的控件给出,并提供了DOM
接口,用于访问Browser
的内容,相对来说SWT
中的Browser
控
件就比较薄弱,没有提供DOM
的可控制接口,那么,如何和控件所加载的页面进行交互呢?比如需要在集成web
应用的环境中实现模拟登陆、自动填表等功能。
SWT
中对Browser
有不同的实现,目前实现的有IE
和Mozilla
。在Browser
的构造函数中根据不同的平台和不同的style
设置类决定使用哪个类的实现。
org.eclipse.swt.browser.Mozilla
org.eclipse.swt.browser.IE
是已经实现的,而其他的org.eclipse.swt.browser.Safari
org.eclipse.swt.browser.Voyager
则没有实现。
public Browser (Composite parent, int style)
{
super (checkParent (parent), checkStyle (style));
String platform = SWT.getPlatform ();
Display display = parent.getDisplay ();
if ("gtk".equals (platform))
display.setData (NO_INPUT_METHOD, null); //$NON-NLS-1$
String className = null;
if ((style & SWT.MOZILLA) != 0)
{
className = "org.eclipse.swt.browser.Mozilla"; //$NON-NLS-1$ }
else
{ if ("win32".equals (platform) || "wpf".equals
(platform)) { //$NON-NLS-1$ $NON-NLS-2$
className =
"org.eclipse.swt.browser.IE"; //$NON-NLS-1$
}
else if ("motif".equals (platform))
{ //$NON-NLS-1$
className = "org.eclipse.swt.browser.Mozilla"; //$NON-NLS-1$
}
else if ("gtk".equals
(platform))
{
//$NON-NLS-1$
className = "org.eclipse.swt.browser.Mozilla"; //$NON-NLS-1$
}
else if ("carbon".equals (platform))
{ //$NON-NLS-1$
className = "org.eclipse.swt.browser.Safari"; //$NON-NLS-1$
}
else if ("photon".equals (platform))
{ //$NON-NLS-1$
className = "org.eclipse.swt.browser.Voyager"; //$NON-NLS-1$
}
else
{
dispose ();
SWT.error (SWT.ERROR_NO_HANDLES);
}
}
try
{
Class clazz = Class.forName (className);
webBrowser = (WebBrowser)clazz.newInstance ();
}
catch (ClassNotFoundException e) { }
catch (IllegalAccessException e) { }
catch (InstantiationException e) { }
if (webBrowser == null)
{
dispose ();
SWT.error (SWT.ERROR_NO_HANDLES);
}
webBrowser.setBrowser (this);
webBrowser.create (parent, style); }
其中对IE
的实现主要是采用调用IE
的Activex
控件,直接加载IE
,对Mozilla
由于代码过多,本人没有具体研究,其本身开源,有兴趣可以参看。
那么回归主题,如何实现与Browser
控件的交互呢?
其实仔细看Browser
控件的API
,可以发现一个execute()
方法,这个方法适用于在web
文档加载完毕时可以运行javascript code
的。这样的话,交互就变得简单了,因为javascript
是提供dom
的支持的,既然可以调用javascript
,那么就可以调用web
页面 中的每个节点了。控制的问题解决了,可是另外的问题来了。 如何从javascript
的code
里边返回数据呢?
比如我需要将一个
的值返回到java
code
中。其实采用的方法是很投机的,因为execute()
方法返回的结果是true or false
,那么对它做文章是没有用的,我们看其他的api
,可以发现:addStatusTextListener()
方法。
这个方法可以监听web
页面对于statusbar
文本改变的值,并反映在java code
里面,那么我们只要通过javascript
把返回的值写到window.status
,那么就可以在javacode
里取到了。 具体代码请参考下面,对于Browser
的继承重写,通过getValue
可以取得指定id
的html
控件的值,通过setValue
可以设置值。
import
org.eclipse.swt.browser.Browser;
import
org.eclipse.swt.browser.StatusTextEvent;
import
org.eclipse.swt.browser.StatusTextListener;
import
org.eclipse.swt.widgets.Composite;
public class CoolBrowser extends
Browser implements StatusTextListener {
private final String DATA =
"Browser_Data";
public CoolBrowser(Composite
parent, int style)
{
super(parent, style);
addStatusTextListener(this);
}
@Override protected void
checkSubclass()
{ }
/** * Get the value of one input
control in the web
@param id *
@return */
public String getValue(String id)
{
if
(execute("var obj = document.getElementById('" + id + "');"
+ "if( obj != null ) window.status=obj.value;"))
{ return (String) getData(DATA); }
return null; }
/** * Set the value of the input control
l
@param id * @param value */
l
public void setValue( String id, Object value
)
l
{ if (execute("var obj = document.getElementById('" + id +
"');" + "if( obj != null ) obj.value='" + value +
"';")) { }
}
l
@Override public void changed(StatusTextEvent
event) { setData(DATA, event.text); } }