• 设为首页
  • 点击收藏
  • 手机版
    手机扫一扫访问
    迪恩网络手机版
  • 关注官方公众号
    微信扫一扫关注
    公众号

Delphi实现HTMLWebBrowser实现HTML界面

原作者: [db:作者] 来自: [db:来源] 收藏 邀请

HTML的界面有以下特点:图文混排,格式灵活,可以包含Flash、声音和视频等,实现图文声像的多媒体界面,而且易于建立和维护。另外,HTML的显示环境一般机器上都具备,通常不需要安装额外的软件。当然,HTML界面也有它欠缺的方面,即:界面控制能力有限,代码调试不便----虽然DHTML提供了比较强的编程特性,但是比起Delphi的传统的开发语言和工具来,对界面的控制能力,尤其是和数据交互时的控制能力还是稍逊一筹。 
了解了这些特点,我们就可以在实际应用开发中,适时地选择HTML技术。下面举个例子: 
一种仪器的管理程序,需要显示该仪器的操作方法文档,包含文字和图片,并要求可以隐藏或显示文档,并能安要求打印。 
这个应用中,图文显示、隐藏/显示部分文档、图文打印等需求,都是HTML界面所擅长的,用传统的表单控件实现几乎无法想像。 
  
用什么实现HTML的界面 
用Delphi实现HTML界面的应用主要有两种选择:WebBrowser Control或MSHTML。为了弄清两者如何选择,我们先来看看Internet Exporer 4.0及其后续版本的体系结构: 
http://msdn.microsoft.com/workshop/graphics/IE4Arch.gif" width=305 border=0> 
IE浏览器是建立在SHDOCVW.DLL组件之上的,而SHDOCVW.DLL则建立在MSHTML.DLL组件之上,底层则包括脚本引擎等。SHDOCVW.DLL提供了对活动文档(Active Document)的支持----例如Word等文档可以在IE中显示,并提供导航、in-place*连接、收藏夹、浏览历史和分级内容选择(PICS: Platform for Internet Content Selection)等功能。SHDOCVW.DLL组件虽然也提供了很多接口可以单独使用,但是通常所指的SHDOCVW.DLL就是WebBrowser Control。MSHTML.DLL是实行HTML解析和表现的组件。它通过DHTML对象模型提供对HTML文档的访问。它实现了活动文档服务器接口,可以通过COM接口调用。 
不难看出,WebBrowser在比较高的层次上,提供了更为丰富的功能,因此一般通常编程都采用WebBrower控件。MSHTML只有在需要解析HTML这样的特殊应用中,才推荐使用。微软的MSDN网站上提供了一个使用MSHTML的例子:WalkAll'>http://msdn.microsoft.com/downloads/samples/internet/browser/walkall/default.asp">WalkAll Sample Source Page。 
(*注:In-place链接,是指点击HTML连接时,在相同的WebBrowser实例中显示连接的HTML文档。如果仅使用MSHTML.DLL,点击链接将导致在新的浏览器实例中打开链接的文档。) 
  
如何访问HTML页面的内容 
首先,在Delphi 7.0组件面板的Internet页上,把TWebBrowser组件放到表单上。 
通过执行以下语句装载HTML文档到WebBrowser中进行显示: 
WebBrowser1.Navigate(GetCurrentDir + '\index.htm'); 
隐藏/显示HTML元件代码示例: 

 Pascal Code 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
 
procedure xx();
var 
Doc : IHTMLDocument2; 
element: IHTMLElement; 
begin 
Doc := IHTMLDocument2(WebBrowser1.Document); 
if nil <> Doc then 
begin 
    element := Doc.all.item('T1', 0) as IHTMLElement; 
    if nil <> element then 
    begin 
        if '' = element.style.display then 
        begin
            element.style.display := 'none' 
            else 
            element.style.display := ''; 
        end; 
    end; 
end; 

设置/取值代码示例: 
var 
         Doc : IHTMLDocument2; 
         inputText : IHTMLInputTextElement; 
     begin 
         Doc := IHTMLDocument2(WebBrowser1.Document); 
         if nil <> Doc then 
         begin 
             //如果T1不是IHTMLInputTextElement类型将出错 
             inputText := Doc.all.item('T1', 0) as IHTMLInputTextElement; 
             inputText.value := Edit1.Text; 
             Edit2.Text := inputText.value; 
         end; 
     end; 
提示:关于哪些HTML元件(标记)应该采用什么MSHTML接口进行访问,请参考MSDN Library中的Web Development > Programming and Reusing the Browser > MSHTML Reference > Interfaces and Scripting Objects。 
  
如何调用JavaScript函数(兼谈消息提示框) 
知道了访问HTML内容的方法,就可以通过间接方式调用HTML页面上包含的JavaScript代码。具体实现方式是:在HTML中插入<span></span>等不可见元件,利用它的click事件调用响应的JavaScript函数,然后再Delphi中调用该元件的click过程。 
下面我们就用Delphi调用JavaScript的alert函数来实现消息提示框。首先在HTML中加入: 
<span ></span> 
Delphi中的调用代码如下: 

 Pascal Code 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
 
procedure TForm1.Alert(const Msg : string); 
     var 
         Doc : IHTMLDocument2; 
         Element : IHTMLElement; 
     begin 
         Doc := IHTMLDocument2(WebBrowser1.Document); 
         Assert(nil <> Doc);//一定要先加载HTML 
         Element := Doc.all.item('ShowMessage', 0) as IHTMLElement; 
         if nil <> Element then 
         begin 
             Element.innerText := Msg; 
             Element.click; 
         end; 
     end; 

我发现在Delphi中用Browser显示HTML,如果你的表单是作为EXE运行,然后嵌入到了别的表单的组件上显示的,例如,Form1.Parent := Form2.Panel1,即Form1显示在Form2中Panel1所占据的位置,当你用ShowMessage显示提示信息时,HTML的内容依然可以被操作,这显然不太好。使用JavaScript中的alert函数则可避免这种现象。 
  
如何禁止右键菜单(如何禁止用户查看源代码) 
默认情况下,在显示HTML的WebBrowser上点击鼠标右键,会显示一个弹出菜单,和IE中看到的一样。通过这个菜单用户可以查看HTML的源代码。因此有时候我们需要屏蔽该菜单。和该菜单相关的接口是IEDocHostUIHandler。已经用人对它进行了封装,详见ieConst.pas'>http://members.shaw.ca/iedelphi/downloads/source/ieConst.pas">ieConst.pas 和 IEDocHostUIHandler.pas'>http://members.shaw.ca/iedelphi/downloads/source/IEDocHostUIHandler.pas">IEDocHostUIHandler.pas。使用方法如下: 

 Pascal Code 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
 
var 
       Form1: TForm1; 
       FDocHostUIHandler: TDocHostUIHandler; 
     ... 
     implementation 
     ... 
     procedure TForm1.FormCreate(Sender: TObject); 
     begin 
       FDocHostUIHandler := TDocHostUIHandler.Create; 
     end; 
     procedure TForm1.FormClose(Sender: TObject; var Action: TCloseAction); 
     begin 
       FDocHostUIHandler.Free; 
     end; 
     procedure TForm1.WebBrowser1NavigateComplete2(Sender: TObject; 
       pDisp: IDispatch; var URL: OleVariant); 
     var 
       hr: HResult; 
       CustDoc: ICustomDoc; 
     begin 
       hr := WebBrowser1.Document.QueryInterface(ICustomDoc, CustDoc); 
       if hr = S_OK then 
         CustDoc.SetUIHandler(FDocHostUIHandler); 
     end; 

有时你可能还需要定制自己的右键菜单,这是还是要借助于IEDocHostUIHandler,具体实现方法可以看看MSDN Library。 
  
如何响应HTML的事件(如何在HTML中调用Delphi的代码) 
HTML事件的响应方式有两种:一种是JavaScript,一种是在Delphi中响应。一些简单的功能可以在JavaScript中实现,这样易于修改。但是从功能、安全性等方面考虑,通常还是要在Delphi中实现。例如当用户点击HTML上的一个按钮时,需要访问数据库,这是就得用Delphi了。 
在Delphi中响应HTML事件,实际上就是响应ActiveX事件的问题,这通过事件槽(Event Sink)来实现,有些繁琐。还好前人已经为我们作了很多工作。利用Experts Exchange网站的Cynna封装的TDHTMLEvent类(该源码请看本文的附件),实现就简单多了。实现代码如下: 

 Pascal Code 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
 
var 
       Form1: TForm1; 
       EventSink: TDHTMLEvent; 
     ... 
     implementation 
     ... 
     procedure TForm1.FormCreate(Sender: TObject); 
     begin 
       EventSink:= TDHTMLEvent.Create; 
     end; 
     procedure TForm1.FormClose(Sender: TObject; var Action: TCloseAction); 
     begin 
       EventSink.Free; 
     end; 
     procedure TForm1.DemoEventSink(Sender: TObject); 
     begin 
         ShowMessage('成功从HTML中调用Delphi的过程。'); 
     end; 
     procedure TForm1.WebBrowser1DocumentComplete(Sender: TObject; 
         const pDisp: IDispatch; var URL: OleVariant); 
     var 
         Doc : IHTMLDocument2; 
         Element : IHTMLElement; 
     begin 
         Doc := IHTMLDocument2(WebBrowser1.Document); 
         if nil <> Doc then 
         begin 
             //找到HTML元件 
             Element := Doc.all.item('B3', 0) as IHTMLElement; 
             //使HTML元件的click事件和DemoEventSink过程关连 
             Element.onclick := EventSink.HookEventHandler(DemoEventSink); 
         end; 
     end; 

点击HTML页面中ID为'B3'的按钮,就会调用DemoEventSink过程。 
  
如何能在HTML控件上输入回车 
含有多行文本输入框(textarea )或提交(submit)按钮的HTML表单在TWebBrowser中显示时,对回车键不响应。另外,Delphi表单上按钮的快捷字母键也无法在HTML表单上输入,因为一输入就触发相应按钮的单击事件。解决代码如下: 

 Pascal Code 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
 

unit Unit1; 
interface 
uses 
   Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms, 
   Dialogs, OleCtrls, SHDocVw_TLB, ActiveX, StdCtrls; 
type 
   TForm1 = class(TForm) 
     WebBrowser1: TWebBrowser; 
     Button1: TButton; 
     Button2: TButton; 
     procedure FormDestroy(Sender: TObject); 
     procedure FormCreate(Sender: TObject); 
     procedure Button1Click(Sender: TObject); 
     procedure Button2Click(Sender: TObject); 
   private 
     { Private declarations } 
     FOleInPlaceActiveObject: IOleInPlaceActiveObject; 
     procedure MsgHandler(var Msg: TMsg; var Handled: Boolean); 
   public 
     { Public declarations } 
   end; 
var 
   Form1: TForm1; 

implementation 
{$R *.dfm} 
procedure TForm1.FormDestroy(Sender: TObject); 
begin 
   FOleInPlaceActiveObject := nil; 
end; 
procedure TForm1.FormCreate(Sender: TObject); 
begin 
   Application.OnMessage := MsgHandler; 
end; 
procedure TForm1.MsgHandler(var Msg: TMsg; var Handled: Boolean); 
const 
   DialogKeys: set of Byte = [VK_LEFT, VK_RIGHT, VK_BACK, VK_UP, VK_DOWN, 
     $30..$39, $41..42, $44..$55, $57, $59..$5A]; 
var 
   iOIPAO: IOleInPlaceActiveObject; 
   Dispatch: IDispatch; 
begin 
   { exit if we don't get back a webbrowser object } 
   if (WebBrowser1 = nil) then 
   begin 
     Handled := System.False; 
     Exit; 
   end; 
   Handled := (IsDialogMessage(WebBrowser1.Handle, Msg) = System.True); 
   if (Handled) and (not WebBrowser1.Busy) then 
   begin 
     if FOleInPlaceActiveObject = nil then 
     begin 
       Dispatch := WebBrowser1.Application; 
       if Dispatch <> nil then 
       begin 
         Dispatch.QueryInterface(IOleInPlaceActiveObject, iOIPAO); 
         if iOIPAO <> nil then 
           FOleInPlaceActiveObject := iOIPAO; 
       end; 
     end; 
     if FOleInPlaceActiveObject <> nil then 
       if ((Msg.message = WM_KEYDOWN) or (Msg.message = WM_KEYUP)) and 
         (Msg.wParam in DialogKeys) then 
         // nothing - do not pass on the DialogKeys 
       else 
         FOleInPlaceActiveObject.TranslateAccelerator(Msg); 
   end; 
end; 
initialization 
   OleInitialize(nil); 
finalization 
   OleUninitialize; 
  

本段代码出自SwissDelphiCenter.ch,作者未知。主要要引用ActiveX。Delphi 7中SHDocVw_TLB改为SHDocVw。 
  
如何实现HTML的打印和预览 
HTML的打印和预览向来是个难题,但自从IE5.5推出后,情况大有改观。你可以利用其“打印模板”功能,实现自己的预览窗口和控制打印。“打印模板”的使用方法请参考MSDN Library中的Web Development > Programming and Reusing the Browser > Print Templates目录下的文章。从微软的网站上还可以下载到一个不错的例子,示例如何一步步由浅入深地使用Print Template (下载:http://download.microsoft.com/download/6/8/3/683DB9FE-8D61-4A3C-B7B8-3169FF70AE9F/printtemplates.exe">打印模板示例)。 
你会发现,要自己实现一个功能完善的打印模板也并非易事。IE浏览器本身带的打印模板做得还不错,能否在它的基础上加上自己的定制功能呢?答案是肯定的,至少从技术上看是这样(不考虑版权问题)。下面就介绍这偷懒的招。 
用Visual Studio打开x:\Program Files\Internet Explorer\MUI\0804\SHDOCLC.DLL,会看到其资源目录。其中HTML/PREVIEW.DLG就是IE所带的打印模板了。把它export(导出)出来,把文件扩展名改成HTM,打开看看,是不是特刺激?PREVIEW.DLG用到了几个图片文件,在2110目录下,别忘了导出。(注:我的环境是Windows XP Professional英文版+SP1a,IE是6.0sp1。) 
IE默认的模版中,页眉页脚均只支持纯文字。下面以定制HTML页眉为例,看看如何定制自己的打印模板。思路是:用自己的页眉内容换掉原有的内容,并修改其页眉高度和页边距使之和新的页眉相对应。 
第一步,定义页眉。在要使用此模版预览打印的HTML文件中加入一个id为Header的div标记,括起HTML页眉内容,并制定以英寸为单位的页眉的高度和宽度,其中宽度应该和模版相符。例: 
<div HTML\\”,然后就可以另存成以制表符分隔的文本文件了。 
最后,用文本编辑器把上一步处理好的文件打开,不用我多说,只要几个替换,就得到所需要的资源脚本了。对于不同目录下的文件,均需要这么弄以下。 
资源脚本弄好了,把资源文件也加入(不是作为资源加入)工程,编译,就得到打包好的DLL文件了。接下来的问题是,这个DLL怎么用啊?别急,WebBrowser支持一种叫res的协议,可以访问文件里的资源。例如,假设上面About.htm打包到了myresource.dll文件中,则可以通过res://myresource.dll/About.htm访问,image016.gif则可通过res://myresource.dll/images/image016.gif访问(注意到了吧,HTML在根目录下,而IMAGES等其它资源则在同名目录下)。如果About.htm中通过“images/image016.gif”引用了image016.gif文件,则该图片在WebBrowser中正常显示。换句话说,你在打包之前,程序可以通过file://...访问HTML,打包之后,只需要换成res://...就可以了----打包对程序和HTML几乎没什么影响。但是,切记,切记!千万不要仅以数字来做文件名(如:1.htm、2.gif等),因为数字是被用来标识某种资源或某个资源的,如果用仅用数字作文件名(可以用字母+数字),打包后会导致访问找不到文件。

参考:http://m.blog.csdn.net/blog/fghydx/18548257


鲜花

握手

雷人

路过

鸡蛋
该文章已有0人参与评论

请发表评论

全部评论

专题导读
上一篇:
关于delphi类的属性定义property方法发布时间:2022-07-18
下一篇:
initialization和finalization-[Delphi]发布时间:2022-07-18
热门推荐
阅读排行榜

扫描微信二维码

查看手机版网站

随时了解更新最新资讯

139-2527-9053

在线客服(服务时间 9:00~18:00)

在线QQ客服
地址:深圳市南山区西丽大学城创智工业园
电邮:jeky_zhao#qq.com
移动电话:139-2527-9053

Powered by 互联科技 X3.4© 2001-2213 极客世界.|Sitemap