偶然的机会需要使用TWebBrowser,在开发过程中涉及到一些比较不肤浅的东西,于是免不了搜资料,翻CSDN的帖子,终于把要做的东西作了出来,同时对于TWebBrowser也有了初步的了解。同时看到很多CSDN上的不少朋友也在TWebBrowser上存在很多疑问,于是把自己这段时间所得的拿出来与大家分享。还是那句话,本人水平很洼,说的不对的话敬请指出,不要客气,否则不但我自己学错了东西,也让看这篇文章的人误入歧途。废话少说正文开始。
首先我们要认识到TWebBrowser其实是Delphi对Internet Explorer Browser的封装,也就是说它是一个ActiveX控件,看过TWebBrowser代码的朋友会发现这个空间的所有方法的实现部分都调用了DefaultInterface的方法,而TWebBrowser的这个属性是一个IWebBrowser2接口类型的对象,这个接口就是IE的接口。我们在使用TWebBrowser代替IE浏览器的目的大部分是为了能够让程序处理页面,实现自动对WebApplication的请求,所以我们首先想得到的就是TWebBrowser所浏览的内容。TWebBrowser的Documnet属性正是这一内容,Document其实是一个IHTMLDocument2,但是它被声明为IDispatch接口类型,我们需要把它转化为IHTMLDocument2类型然后是用我们需要的各种方法。在这里需要注意IHTMLDocument2是在MSHTML单元定义的,需要我们手动将这一单元加入到uses部分。具体代码如下:
var D : IHTMLDocument2;
begin
D := WebBrowser1.Document as IHTMLDocument2;
end;
接下来我们来看看一个网页中包含什么,也就是我们希望通过TWebBrowser来处理的内容有哪些。网页中的元素主要有普通文本内容,超级连接以及动态的元素(Form中的元素),当然还有其它元素,但是我们在一般的处理过程中一般会用到这些,因此我在这里以这些元素为例首先我要介绍的是Form和包含在Form中的元素的使用。
在IHTMLDocument接口中有一个Forms的属性,这个属性是IHTMLElementCollection接口类型,其实这个Forms属性是TWebBrowser显示的页面中的所有Form元素。也就是说一个页面中的所有Form都包含在Forms这个集合中。我们可以以使用IHTMLDocument.Forms.item(name: OleVariant; index: OleVariant)得到我们需要操作的Form,当然我们在这里得到的只是一个IDispatch接口,我们需要再把这个接口转换成IHTMLFormElement来使用Form的方法和属性。示例如下(该例子为yahoo的免费信箱登陆界面http://mail.yahoo.com.cn):
var Form : IHTMLFormElement ;
D:IHTMLDocument2 ;
begin
with WebBrowser1 do begin
D := Document as IHTMLDocument2;
Form := D.Forms.item('login_form',0) as IHTMLFormElement;
(form.item('login',0) as IHTMLElement).setAttribute('value',edit1.Text,0);
(form.item('passwd',0) as IHTMLElement).setAttribute('value',edit2.Text,0);
//form.submit; // this line work too
(form.item('.save',0) as IHTMLElement).click;
end;
end;
从上面的例子我们可以看到我们可以通过两种方法提交一个Form,这两种方法在一般情况下没有什么区别,但是当页面中编写了一些js用来实现页面提交的控制时,前者会忽略掉这些js,所以后面的方法是我所推荐的。
在这个时候我遇到了一个问题,就是在我要处理的页面中有两个Form,而且这样两个Form都没有名字,也就是说Form := D.Forms.item('login_form',0) as IHTMLFormElement;这一句中item的第一个参数的我们无法从网页中得到,同时在设置这个参数时我发现了一个问题,就是说如果在页面中有两个Form元素的话,第一个Form元素可以通过item(varEmpty,0)得到,第二个Form元素可以通过item(verNull,0)得到,而item的第二个参数完全不起作用,这个问题可能是由于我对该函数的错误使用造成的,希望有人可以给出这一问题的解决方案(我在自己翻看帖子是找到了答案,的确是我对该函数的参数的错误使用造成的,第一个参数应该是我们要使用的对象的索引值。)。我的想法是DHTML在没有明确得到一个元素的名称时会自动生成一个唯一的元素名称分配给该元素,但是如何得到这个唯一的元素名称呢?这个只是我的一个设想,我们会看到,当我们处理链接的时候我们还要遇到这个问题。示例如下(
这是我自己做的一个jsp程序):
var form : IHTMLFormElement ;
d:IHTMLDocument2 ;
begin
with WebBrowser1 do begin
d := document as IHTMLDocument2;
form := d.forms.item(varNull,01) as IHTMLFormElement;
(form.item('firstName',0) as IHTMLElement).setAttribute('value',edit1.Text,0);
(form.item('lastName',0) as IHTMLElement).setAttribute('value',edit1.Text,0);
form.submit;
end;
end;
以上是网页中Form的基本处理,接下来我介绍一下网页中对于链接的控制,我们一般是希望能够实现程序自动点击网页中的连接。在这里正如前面提到的,我只能得到前两个没有名称的连接。示例如下:
var Links : IHTMLElementCollection;
D:IHTMLDocument2 ;
Element : IHTMLElement;
begin
with WebBrowser1 do begin
D := Document as IHTMLDocument2;
Links := D.links;
Element := (Links.Item(varempty,0) as IHTMLElement);
ShowMessage(Element.getAttribute('href',0));
Element := (Links.Item(varNull,0) as IHTMLElement);
ShowMessage(Element.getAttribute('href',0));
end;
end;
我们可以通过调用以上代码中的Element.Click事件来模拟点击。不行了,写不下去了,还有一个常见的问题就是怎么使自己写的Browser在打开一个新窗口时在制定窗口打开。这个要在TWebBrowser的NewWindows2中改变 ppDisp来实现。
就是这么多,希望大家能够从中学到点什么,更希望有人能够解答我上面的疑问。
===============================================================================
TWebBrowser的常见属性和方法
GoBack:方法,后退到上一个页面。
GoForward:方法,前进到下一个页面。
GoHome:方法,调用默认的主页页面,该页面在IE的选项中设定。
GoSearch:方法,调用默认的搜索页面,该页面在IE的选项中设定。
Refresh:方法,刷新当前页面。
Stop:方法,停止调用或打开当前页面。
LocationName:属性(WideString),当前位置的名称。
LocationURL:属性(WideString),当前位置的URL。
Busy: 属性(Boolean),是否正忙。
Visible: 属性(Boolean),浏览器窗口是否可见。
(以下属性为在TWebBrowser新增,
TWebBrowser_V1中没有,其作用有待探索)
StatusBar: 属性(Boolean),是否显示状态栏。
StatusText: 属性(WideString),状态栏内容。
ToolBar: 属性(SYSINT),工具栏中的内容。
MenuBar: 属性(Boolean),是否显示菜单条。
FullScreen: 属性(Boolean),是否全屏显示。
Offline: 属性(Boolean),是否脱机浏览。
AddressBar: 属性(Boolean),是否显示地址栏。
Navigate(const URL: WideString;var Flags, TargetFrameName, PostData, Headers: OleVariant):方法,调用指定页面
具体参数如下:
URL:指定页面的URL。
Flags:Word类型,作用还不清楚,可设为0。
TargetFrameName:WideString打开页面所在的Frame,为空字符串时在当前的Frame中打开;TargetFrameName指定的Frame存在时在Frame中打 开;TargetFrameName指定的Frame不存在时则新建一个窗口打开,此时就相当于调用外部的IE浏览器了。
PostData:boolean,是否允许发送数据。
Headers:WideString,要发送的URL请求的头部数据。
TWebBrowser的常见事件主要有:
OnStatusTextChange = procedure(Sender: TObject; const Text: WideString) of object;
在状态栏提示信息变化时发生,参数Text为当前状态栏提示信息,我们可以根据该信息来更新我们自己的状态栏提示信息或处理其它的事务.
OnProgressChange = procedure(Sender: TObject; Progress, ProgressMax: Integer) of object;
在打开页面的进度变化时发生,参数Progress为当前进度,ProgressMax为总进度,我们可以根据这两个参数来更新我们自己的状态栏提示信息或处理其它的事务.
OnCommandStateChange = procedure(Sender: TObject; Command: Integer; Enable: WordBool) of object;
当执行新的命令时发生,Command为命令标识,Enable为是否允许执行该命令. OnTitleChange = procedure(Sender: TObject; const Text: WideString) of object;
在页面的标题发生变化时发生,Text为当前标题.
OnPropertyChange = procedure(Sender: TObject; const Property_: WideString) of object;
在页面的属性发生变化时发生,Property_为属性名称 OnDownloadComplete: TNotifyEvent
在下载页面完成后发生.
OnDownloadBegin: TNotifyEvent
在下载页面开始前发生.
在Delphi程序中应用IE浏览器控件的两个例子
(1)制作自己的帮助系统
我们利用IE浏览器控件为用户制作了一个帮助系统,帮助文件由多个HTML文件组成,一个主题对应一个 HTML文件(Topic.HTM),每个主题下的项目对应HTML文件中的一个标签(#Item)。这样在我们的系统中,就不必再调用IE浏览器或WinHelp程序来为用户提供帮助了。相信大家知道HTML帮助文件与传统的HLP帮助文件相比的优势所在吧。
在下面例子中,演示了TWebBrowser(IE4浏览器控件)的Navigate方法的使用方法。请注意程序中的注释。(下面为程序的主要片段)。
{根据主题和项目调用帮助文件}
procedure ShowHelp
( HelpTopic,HelpItem : String );
var
TargetFrameName,PostData,
Heads,Flags : OleVariant;
URL : widestring;
begin
TargetFrameName := '';{指定Frame的空字符串时,
则在当前Frame中打开帮助文件}
PostData := false;{不发送数据}
Heads := '';{Header信息为空}
Flags := 0;{Flags设为0}
URL := HelpTopic + '.HTM#'+HelpItem;
{帮助信息的URL}
with formHelp.webbrowser do{在帮助窗口
中的IE浏览器控件中显示帮助信息}
begin
navigate(URL,Flags,TargetFrameName,
PostData,Heads);{显示帮助信息}
end;
end;
(2)显示一个GIF动画
假如你还没有一个适合的动画显示控件,不妨试用一下下面方法.
procedure ShowGIF( GIFFileName : String );
var
TargetFrameName,PostData,Heads,Flags : OleVariant;
URL : widestring;
begin
TargetFrameName := '';{指定Frame的空字符串时,
则在当前Frame中打开动画文件}
PostData := false;{不发送数据}
Heads := '';{Header信息为空}
Flags := 0;{Flags设为0}
URL := GIFFileName;
with formGIF.webbrowser do{在指定窗口中的
IE浏览器控件中显示动画}
begin
navigate(URL,Flags,TargetFrameName
,PostData,Heads);{显示动画文件}
end;
end;
============================================================================