使用IntraWeb进行Web编程

原创 2005年04月26日 10:50:00
使用IntraWeb进行Web编程
《Delphi从入门到精通》第21章 第一部分
概述
自Delphi2以后,Chad Z. Hower就一直在为建立一种简化Web程序开发的Delphi架构而努力,这种简化的核心思想就是使开发Web程序像开发普通窗口程序一样简单并且可视化。一些程序员了解动态HTML、JavaScript、 Cascading Style Sheets和最新的互联网技术;而另一些程序员则想像创建VCL和CLX应用程序那样创建Web程序。
IntraWeb就是应第二种开发者的需求而问世的,她功能强大,即便是专业的Web程序员也能够从中受益。用Chad的话来说,IntraWeb是用来开发Web程序而不是用来创建网站的。此外,IntraWeb组件可用于特有的应用程序或者是WebBroker 和 WebSnap应用程序。
在本章我不能详述IntraWeb的每一个细节,因为安装后,在Delphi上分布于数个组件板共计50个组件之多,实在太大了。我计划讲解一下基础内容,您可以有选择地用于您手头的项目或是那些项目中的部分内容。
提示:在Delphi7光盘中有IntraWeb的PDF版手册。如果您找不到,可以到Atozed Software公司的网站上去下载。关于IntraWeb的技术支持,可以参考Borland的新闻组。
IntraWeb简介
IntraWeb是Atozed Software公司出品的组件库。在Delphi7的专业版和企业版中有相应版本的IntraWeb。专业版的IntraWeb只能用于页模式(Page mode),关于页模式本章稍后将会提到。尽管Delphi7是Borland公司的第一版包含该组件集的集成开发环境,但IntraWeb已经发展有几年了,受到了相当好的评价和支持,包括很多第三方组件开发商。
提示:
尽管您不能得到核心源代码(需购买),IntraWeb体系架构是完全开放的。并且所有组件的源代码随意可得。虽然IntraWeb是Delphi标准安装的一部分,但同样适用于Kylix。只要小心编写,IntraWeb程序完全可以实现跨平台的。
注:除了Delphi 和Kylix版外,IntraWeb还有C++ Builder和Java版。.Net版正在开发中,将会随Delphi for .Net(Delphi 8)一起发布。
如果您拥有正版Delphi7,你完全能够收到一个重大的升级信息,并且可以升级到IntraWeb5.1企业版,包括升级文档和技术支持。(目前版本为7.19——译者)
从网站到Web程序
正如前面所讲,IntraWeb背后的思想是构建Web程序而不是网站。当您使用WebBroker和WebSnap时,你以Web pages和Page Producers术语在思考,同时您的工作紧紧地和HTML层次的网页制作联系在一起。而用IntraWeb时,您想的是组件、属性和事件,就像是在Delphi中作可视开发一样。
比如,创建一个新的IntraWeb应用程序,选择File ® New ® Other,在新项目对话框中移到IntraWeb页,然后选择Stand Alone Application。在接下来的对话框中(此对话框是Delphi的而不是IntraWeb的向导)你可以选择一个已经存在的文件夹或是输入一个新文件夹(系统会自动创建,之所以在此提及,是因为该对话框不是很清楚)。最终的程序包含一个项目文件和两个不同的单元(稍后我会讲到它的结构)。
现在,让我们创建一个例程(随书源代码中叫做IWSimpleApp),步骤如下:
1、 移到程序的主窗体,从组件板中的IW Standard页中选择一个按钮,一个文本编辑框和一个列表框添加到窗体。注意不是组件板中Standard页中的VCL组件,而是相应的IntraWeb组件:IWButton,IWEdit和IWListbox。
2、 像下面那样调整它们的属性:
object IWButton1: TIWButton
Caption = ‘Add Item‘
end
object IWEdit1: TIWEdit
Text = ‘four‘
end
object IWListbox1: TIWListbox
Items.Strings = (
‘one‘
‘two‘
‘three‘)
end

3、 双击按钮组件编写OnClick事件,代码如下:
procedure TformMain.IWButton1Click(Sender: TObject);
begin
IWListBox1.Items.Add (IWEdit1.Text);
end;

如图21.1所示的web程序(图中所示的是多两个按钮的最终版本)能够把文本添加到列表框,创建它仅需这几步。当你运行该程序时需要注意的是你每次单击按钮,浏览器都会向程序发送一个新的请求,该请求将会驱动Delphi事件句柄产生一个新的基于窗体上组件新状态的HTML页。
当您执行该程序时,您看不到程序输出的浏览器,而是一个IntraWeb控制器窗口(见图21.2)。一个stand-alone IntraWeb应用程序是一个HTTP服务器,这一点在下一部分里会有详细的阐述。您所看到的这个窗口是由每个stand-alone IntraWeb应用程序的项目文件中默认创建的IWRun函数来调用管理的。您可以在该调试窗口中选择一个浏览器,并通过它来运行程序,或者把URL拷贝到剪切板,然后粘贴到您的浏览器中。程序默认使用一个随机端口,该端口每次执行都不相同,因此,每次执行时的URL都不同。您可以通过选择服务器设计器(有点像数据模块)设定port端口属性来改变这种行为。在该例中我用的是8080(一个普通的HTTP端口),当然,其他值也可以。
IntraWeb程序的代码主要在服务器端,但IntraWeb也能够产生JavaScript来控制程序的一些特性,因此在客户端也可以执行特别的代码。您可以通过使用特别的客户端组件或者写一些特别的JavaScript代码来实现。作为一个比较,下面例程IWSimpleApp中的两个按钮通过不同的方法实现显示一个消息框。
两个按钮中的IWButton2使用Delphi代码利用服务器端事件来显示一个消息框。
procedure TformMain.IWButton2Click(Sender: TObject);
var
nItem: Integer;
begin
nItem := IWListbox1.ItemIndex;
if nItem >= 0 then
WebApplication.ShowMessage (IWListBox1.Items [nItem])
else
WebApplication.ShowMessage (‘No item selected‘);
end;


这两个按钮中的第二个(IWButton3)使用了JavaScript,这是通过在按钮的ScriptEvents属性的属性编辑器中正确地设置JavaScript事件句柄来实现在Delphi程序中嵌入JavaScript的。

IntraWeb事件脚本编辑器
初探幕后
看到了吧,创建一个IntraWeb应用程序就和创建一个基于窗体的Delphi应用程序一样简单:在窗体上放置组件然后处理它们的事件。当然,效果是不同的,毕竟这样的程序是运行在浏览器中。为了让您明白到底是怎样工作的,我们简要地看一下这个简单的程序背后。这样做会帮助您理解设置组件属性和使用组件编程的效果。
这是一个基于浏览器的程序,因此没有什么比看一下程序送到浏览器的HTML代码能更好地理解它工作机制的方式了。打开IWSimpleApp程序源代码页,会发现分成了三部分。第一部分是类似下面的样式列表:
.IWEDIT1CSS {position:absolute;left:40;top:40;z-index:100;
font-style:normal;font-size:10pt;text-decoration:none;}
IntraWeb使用样式不仅能确定每个组件的外观,如字体和颜色,而且能够确定组件的位置,默认方式是相对位置定位。每个样式受组件的很多属性影响,如果您有样式表的知识,您可以简单地试验一下;如果不熟悉样式表,那就相信IntraWeb吧,它会把组件在web页上绘制得很好。
The second block consists of JavaScript scripting. The main script block contains initialization code and the code of client-side event handlers for the components, like the following:
第二块包含了JavaScript的描述。主要的脚本块包含初使化代码和组件的客户端事件处理代码,例如:
function IWBUTTON1_OnClick(ASender) {
return SubmitClickConfirm(‘IWBUTTON1‘,‘‘, true, ‘‘);
}
The scripting section of the page has also references to other files required by the browser and made available by IntraWeb. Some of these files are generic; others are tied to the specific browser: IntraWeb detects the browser being used and returns different JavaScript code and base JavaScript files.
脚本还涉及一些浏览器需要的由IntraWeb产生的其他文件。这些文件有些是通用的,而有些是捆绑给特定的浏览器的:IntraWeb能够探测出所用浏览器,从而返回不同的JavaScript代码和基本JavaScript文件。
注意:因为不是所有浏览器都能识别JavaScript的,所以IntraWeb只支持部分浏览器。支持的浏览器有最新版的Microsoft Internet Explorer、Netscape Navigator和开放源代码的 Mozilla (我用的就是)。由于Opera支持JavaScript更有限,所以默认情况下如被识别,IntraWeb就会发出一个错误信息(依赖于controller的SupportBrowsers属性)。Opera能够和免费的Arcana组件一起使用,在IW 5.1版中被正式支持。记住浏览器可能会伪造身份:比如,Opera常常被认成IE。为使站点不受浏览器的限制,设置支持更多的浏览器,却又可能会导致运行错误和矛盾。
第三部分HTML是定义页面结构的。在Body标记内部是一个带有将要执行的动作的form标记(同一行):
<form onsubmit="return FormDefaultSubmit();" name="SubmitForm"
action="/EXEC/3/DC323E01B09C83224E57E240" method="POST">
form标记依附于指定的用户界面组件,如按钮和编辑框:
<input type="TEXT" name="IWEDIT1" size="17" value="four"
id="IWEDIT1" class="IWEDIT1CSS">
<input value="Add Item" name="IWBUTTON1" type="button"
onclick="return IWBUTTON1_OnClick(this);"
id="IWBUTTON1" class="IWBUTTON1CSS">
窗体还隐藏了一些用于前后传递信息的IntraWeb组件。不过,URL在IntraWeb中是最重要的传递信息方式。在程序中URL类似下面:
http://127.0.0.1:8080/EXEC/2/DC323E01B09C83224E57E240
第一部分是IP地址和stand-alone IntraWeb应用程序端口(使用不同的体系结构将会不一样), EXEC 命令后面是累计请求次数,后面是session ID。稍后我们会讨论Session。但现在我们就可以说IntraWeb使用URL记号代替cookies从而忽略浏览器的设置而使应用程序可用。如果你愿意,可以通过设置controller的TrackMode属性,来使用cookies代替URL标记。
IntraWeb 体系结构
在演示如何使用Delphi7中其他IntraWeb组件之前,让我们来讨论一下IntraWeb的关键东西: Web开发的不同开发模式,即AppMode和PageMode。前者可以开发成一个独立运行的可执行程序,也可以开发成ISAPI DLL,甚至Apache Modules。AppMode能够真正展示IntraWeb的优秀特征。而PageMode则是WebBroker或WebSnap程序的IntraWeb简版插件,可以开发除可执行程序之外的任何程序,如ISAPI、Apache Module、CGI等。IntraWeb基于这两种模式提供了三种不同但又有所交叉的体系结构:
Standalone Mode 提供了一个像第一个例程那样的自己的Web Server。这一点对于调试来说相当便利(你可以在开发环境中直接运行并且可以随处设置断点)。Standalone mode开发的程序可以运行在内联网(Intranets)并且让用户在自己的电脑上脱机使用Web 界面工作。如果带参数 -install 运行stand-alone程序,程序将会以服务形式工作,不显示对话框界面。Standalone mode提供开发使用IntraWeb自身作为Web服务器的AppMode程序的一种方法。
Application Mode 能够开发商务web服务,建立Apache module或是IIS动态链接库。Application mode具备包括会话期管理在内的IntraWeb全部特性,并且是开发通过Web即可升级的网络程序首选。准确地说,Application mode可以开发成为stand-alone程序,ISAPI动态链接库,或是Apache modules。
Page Mode 提供一个整合IntraWeb页面和WebBroker与WebSnap应用程序的方法。Page mode能够向现有的程序或是基于其他技术的动态交互站点注入IntraWeb特性,提供更好的交互手段。Page mode是在CGI程序中使用IntraWeb技术的唯一选择,不过,Page mode不具有会话期管理特性,而具备该特性的Stand-alone IntraWeb程序却不支持Page mode。
本章后面的例子,为了追求简单和调试方便主要使用Stand alone模式。但同时也会涉及Page mode。
《Delphi从入门到精通》第21章 第二部分
创建IntraWeb应用程序
创建IntraWeb应用程序,有很多组件可用。不妨看一下Delphi组件板中的IW Standard页,会给您留下深刻的印象,从简单的按钮、复选框、单选框、编辑框、列表框到迷人的树形控件、菜单、计时器、表格和链接应有尽有。我不想举例描述每个组件的用法,只想通过几个例子,阐述IntraWeb的体系结构,当然顺便也会介绍用到的组件。
我创建了一个例程(叫IWTree),演示了IntraWeb的菜单和树形控件的用法,同时也说明了如何动态创建组件。IntraWeb菜单通过引入常规Delphi菜单内容来工作的,这很容易,只需简单地把AttachedMenu设置成Tmenu组件即可:
object MainMenu1: TMainMenu
object Tree1: TMenuItem
object ExpandAll1: TMenuItem
object CollapseAll1: TMenuItem
object N1: TMenuItem
object EnlargeFont1: TMenuItem
object ReduceFont1: TMenuItem
end
object About1: TMenuItem
object Application1: TMenuItem
object TreeContents1: TMenuItem
end
end
object IWMenu1: TIWMenu
AttachedMenu = MainMenu1
Orientation = iwOHorizontal
end
菜单项运行时处理OnClick事件,是以链接形式实现的。看一下图21.3,这是展示菜单的例程的运行效果。例程中的另外一个组件是树形控件,在例子中预置了很多节点。该组件通过很多JavaScript代码来实现在浏览器中(不需要调用服务器代码)直接控制树形控件节点的展开和收叠。同时,菜单中还有控制树形控件节点展开和收叠以及控制字体大小的菜单项。下面列出其中两个事件代码:
procedure TformTree.ExpandAll1Click(Sender: TObject);
var
i: Integer;
begin
for i := 0 to IWTreeView1.Items.Count - 1 do
IWTreeView1.Items [i].Expanded := True;
end;

procedure TformTree.EnlargeFont1Click(Sender: TObject);
begin
IWTreeView1.Font.Size := IWTreeView1.Font.Size + 2;
end;

图21.3 演示菜单、树形控件和动态创建组件的例程
感谢IntraWeb提供了如同标准Delphi VCL组件的特性,使代码易读,也容易理解。

例程中的菜单有两个子菜单稍微复杂一点。第一个是显示应用程序ID,也就是程序执行时的会话期ID。该标志可以通过全局对象WebApplication的AppID属性获得。第二个子菜单是Tree Contents,它可以把树形控件的一级节点标题和子节点数目清单列出。值得注意的是,这些信息显示在一个运行时才创建的组件memo里(见图21.3),这一点与在一个VCL应用程序里面做同样的事情非常相似。
procedure TformTree.TreeContents1Click(Sender: TObject);
var
i: Integer;
begin
with TIWMemo.Create(Self) do
begin
Parent := Self;
Align := alBottom;
for i := 0 to IWTreeView1.Items.Count - 1 do
Lines.Add (IWTreeView1.Items [i].Caption + ‘ (‘ +
IntToStr (IWTreeView1.Items [i].SubItems.Count) + ‘)‘);
end;
end;

提示:请注意IntraWeb的alignment属性和VCL组件的alignment非常相似。比如程序菜单的alignment属性是alTop,而tree组件则是alClient,此外动态创建的memo的alignment属性被设为alBottom。作为替代方法,可以使用anchors(同样VCL中也有):可以创建一个bottom-right按钮,或者在页面中间的组件,只需把组件的四个anchors全设为true。请看下面关于该技术的例程。
Writing Multipage Applications
开发多页面应用程序
目前所讲的例程都只有一个页面,下面我们来创建IntraWeb程序的第二个页面。其实,就是这种情况,IntraWeb开发工具也与标准Delphi(或Kylix)十分相似,而与其他互联网开发工具十分不同。下面的例子可以通过IntraWeb向导自动产生源代码,接着研究我们关心的这些代码。
我们从头看,例程IWTwoForms的主窗体演示了IntraWeb表格特性。这是一个强大的组件,她产生的HTML表格既可放入文本又可放入其他组件。在本例中,程序开始运行时,填充表格的内容(在主窗体的OnCreate事件中处理):
procedure TformMain.IWAppFormCreate(Sender: TObject);
var
i: Integer;
link: TIWURL;
begin
// set grid titles
IWGrid1.Cell[0, 0].Text := ‘Row‘;
IWGrid1.Cell[0, 1].Text := ‘Owner‘;
IWGrid1.Cell[0, 2].Text := ‘Web Site‘;
// set grid contents
for i := 1 to IWGrid1.RowCount - 1 do
begin
IWGrid1.Cell [i,0].Text := ‘Row ‘ + IntToStr (i+1);
IWGrid1.Cell [i,1].Text := ‘IWTwoForms by Marco Cantù‘;
link := TIWURL.Create(Self);
link.Text := ‘Click here‘;
link.URL := ‘http://www.marcocantu.com‘;
IWGrid1.Cell [i,2].Control := link;
end;
end;
上面这段代码的运行结果见图21.4,除了输出外,还有几件事值得注意。首先,表格使用了Delphi的anchors属性(全设为false)来使表格始终处在页面中间,即使用户改变了浏览器窗口大小。其次,我在第三列中加入了一个IWURL组件,当然也可以放其他组件(包括按钮和编辑框)。

图21.4 例程IWTwoForms使用的表格组件嵌入文本和IWURL组件
第三,也是最值得研究的是IWGrid组件转换成了带框架和不带框架的HTML表格。这是表格中的一行HTML代码片断:
<tr>
<td valign="middle" align="left" NOWRAP>
<font style="font-size:10pt;">Row 2</font>
</td>
<td valign="middle" align="left" NOWRAP>
<font style="font-size:10pt;">IWTwoForms by Marco Cantù</font>
</td>
<td valign="middle" align="left" NOWRAP>
<font style="font-size:10pt;"></font>
<a href="#" onclick="parent.LoadURL(‘http://www.marcocantu.com‘)"
id="TIWURL1" name="TIWURL1"
style="z-index:100;font-style:normal;font-size:10pt;text-decoration:none;">
Click here</a>
</td>
</tr>
提示:在上面的代码清单中,我们注意到URL是通过JavaScript来激活链接的,而不是直接的超链接。由于IntraWeb允许客户端所有动作,比如确认、检查和提交,而这些动作都依赖于JavaScript。例如,如果你把一个组件的Required设成true,则该组件如果没有任何数据就不能提交,此时如果提交将会看到一个JavaScript错误信息(使用组件的FriendlyName属性来定制的消息框)。
本例的核心特性是它显示第二个页面的能力。为了实现这一点,首先需要给程序添加一个IntraWeb页,方法是单击File->New->Other…,启动Delphi的New Items对话框,翻到IntraWeb页,选择Application Form,单击“Ok”按钮完成添加工作。接着向该窗体上放一些组件,然后在主窗口中放置一个按钮或其他控件用来显示第二个窗体:
procedure TformMain.btnShowGraphicClick(Sender: TObject);
begin
anotherform := TAnotherForm.Create(WebApplication);
anotherform.Show;
end;
即使程序调用了Show方法,也会被看成是调用了ShowModal。这是因为IntraWeb把页面当成堆栈来处理。最后显示的页面在栈顶,同时显示在浏览器上。如果关闭该页(隐藏或销毁),就会显示该页的前一页。在本例中,第二页的关闭是通过调用Release方法,该方法在VCL程序中是结束正在运行的窗体的恰当方法。你也可以隐藏第二个窗体然后再显示它从而避免每次都重建窗体的实例。
警告:在例程中的主窗体上放置了一个Close按钮,但该按钮没有调用Release方法,而是调用了WebApplication对象的Terminate方法。该方法可以传递输出信息,如WebApplication.Terminate(‘goodbye’);例程中使用了另一种替换方法:TerminateAndRedirect。
现在已经知道如何创建带有两个窗体的IntraWeb程序,接着我们简要地考查一下IntraWeb是如何创建主窗体的。当创建一个新程序时,在项目文件里有由IntraWeb向导产生的相关代码:
begin
IWRun(TFormMain, TIWServerController);
这一行不同于Delphi的标准项目文件,因为它调用了一个全局函数而不是应用全局对象的方法。函数的两个参数分别是主窗体的类和IntraWeb控制器的类。该控制器能够处理会话期和许多特性,稍后就会介绍。
例程中的第二个窗体显示了IntraWeb另外一个有趣的特性:图形支持。该窗体有一个显示雅典娜神像的图形组件,这是通过把一个位图装载进一个IWImage组件中实现的:Intraweb把这个位图转换成JPEG格式,并存到创建于程序所在文件夹内的cache文件夹中,然后再返回该JPEG文件的引用。其相应HTML代码如下:
<img src="/cache/JPG1.tmp" name="IWIMAGE1" border="0" width="153" height="139">

该例程使用的IntraWeb另外一个特性是用户可以用鼠标点击图像,并通过运行服务器端代码来实现修改图像的功能。在本例中,修改的结果是画绿色的小圆圈。

代码如下:
procedure Tanotherform.IWImage1MouseDown(ASender: TObject;
const AX, AY: Integer);
var
aCanvas: TCanvas;
begin
aCanvas := IWImage1.Picture.Bitmap.Canvas;
aCanvas.Pen.Width := 8;
aCanvas.Pen.Color := clGreen;
aCanvas.Ellipse(Ax - 10, Ay - 10, Ax + 10, Ay + 10);
end;
警告:绘制操作是发生在位图的画布(canvas)上。不要使用Image组件的画布(在VCL组件Image中是可以这样做的),也不要使用JPEG图像,否则不是没有响应就是出运行错误。
会话期管理
注:Session就是通话、话路。在打电话的时候,通常情况下每一对用户拥有一个话路,否则就会“窜线”了。在本章中,Session就是指客户端的一个用户和服务器交互的话路,或者称为交互通道。由于其他书籍中把Session译作“会话期”,这里沿用该译法。——译者。
如果你有一些Web编程经验,就会知道会话期管理是一个复杂的话题。IntraWeb提供预定义的会话期管理并且简化使用会话期的方法。如果在一个指定的窗体中需要会话数据,需要做的是给该窗体加一个域。IntraWeb窗体和组件会为每一个会话期创建一个实例。比如,在例程IWSession中,我给窗体添加一个域叫做FormCount,为了对比,我又在全局单元里声明一个全局变量GlobalCount,这个变量会被程序的所有实例所共享。
为了加强对会话数据的控制同时让多个窗体共享它,可以定制TuserSession类,该类是IntraWeb应用程序向导在ServerController单元中自动产生的。在例程IWSession中,我是这样定制的:
type
TUserSession = class
public
UserCount: Integer;
end;
IntraWeb 为每个新的会话期创建对象的实例,参阅ServerController单元中TIWServerController类的IWServerControllerBaseNewSession方法:
procedure TIWServerController.IWServerControllerBaseNewSession(
ASession: TIWApplication; var VMainForm: TIWAppForm);
begin
ASession.Data := TUserSession.Create;
end;
在代码中,会话期对象可以通过访问RwebApplication这个全局变量的Data域来引用,这个变量通常用来访问当前用户的会话期。
提示:RwebApplication是线程变量,在IWInit单元中定义。她提供了访问会话期数据的线程安全方法:在多线程环境下访问它需要倍加小心。该变量可以在窗体和控件之外使用(基于线程的),这就是为什么主要用在数据模块、全局程序和非IntraWeb类内的原因。
此外,默认的ServerController单元提供一个可用的辅助函数:
function UserSession: TUserSession;
begin
Result := TUserSession(RWebApplication.Data);
end;
因为大多数代码已经自动产生了,像下面从例程IWSession中提取的代码那样,只需给TuserSession类添加数据,就可用通过UserSession函数简单地应用了。在例程中,单击按钮,程序会累加几个计数器(一个全局变量,两个会话期指定的)并通过标签显示它们的值:
procedure TformMain.IWButton1Click(Sender: TObject);
begin
InterlockedIncrement (GlobalCount);
Inc (FormCount);

Inc (UserSession.UserCount);

IWLabel1.Text := ‘Global: ‘ + IntToStr (GlobalCount);
IWLabel2.Text := ‘Form: ‘ + IntToStr (FormCount);
IWLabel3.Text := ‘User: ‘ + IntToStr (UserSession.UserCount);
end;
注意,程序通过调用Windows的InterlockedIncrement来避免被多线程所共享的全局变量发生访问冲突。也可以通过使用critical section或者是TidThreadSafeInteger(见于IdThreadsafe单元)来避免这种情况。
图21.5显示了程序的输出(通过两个不同的浏览器创建两个会话期),程序还有一个复选框,用来激活计时器。听起来挺不可思议的,但实际上在IntraWeb程序中,计时器就和Windows中的计时器一样工作。当计时器的时间间隔到期时,相应的代码就会被执行。在网页中,这意味着触发JavaScript代码来刷新页面:
IWTIMER1=setTimeout(‘SubmitClick("IWTIMER1","", false)‘,5000);

图21.5、运行在两个不同浏览器中的IWSession例程
与WebBroker和WebSnap整合
到目前为止,只讲了如何创建stand-alone模式的IntraWeb应用程序。当你需要开发IIS或是Apache下的IntraWeb动态链接库时,情形也基本一样。但是,如果你想用IntraWeb技术来拓展已有的WebBroker(或是WebSnap)程序,情况就不一样了。
两种技术的桥梁是IWPageProducer组件。该组件像其他页生成器组件一样依附于WebBroker的action,同时可以使用一个特殊的事件来创建并获得一个IntraWeb窗体:
procedure TWebModule1.IWPageProducer1GetForm(ASender: TIWPageProducer;
AWebApplication: TIWApplication; var VForm: TIWPageForm);
begin
VForm := TformMain.Create(AWebApplication);
end;
仅一行代码,就能实现IntraWeb页嵌入WebBroker程序,在例程CgiIntra中也是如此。IWModuleController对IntraWeb支持提供核心服务。每个IntraWeb项目都必须有这种组件才能正确地工作。
警告:Delphi7中发行的IntraWeb的IWModuleController组件和Delphi的Web App Debugger有冲突,但问题已经解决,可以免费更新。
这是例程的web module窗体摘要:
object WebModule1: TWebModule1
Actions = <
item
Default = True
Name = ‘WebActionItem1‘
PathInfo = ‘/show‘
OnAction = WebModule1WebActionItem1Action
end
item
Name = ‘WebActionItem2‘
PathInfo = ‘/iwdemo‘
Producer = IWPageProducer1
end>
object IWModuleController1: TIWModuleController
object IWPageProducer1: TIWPageProducer
OnGetForm = IWPageProducer1GetForm
end
end
因为这是一个页模式的CGI程序,所以没有会话期管理。此外,页面的组件状态不能像标准IntraWeb程序那样通过事件处理来自动更新。为了达到同样的效果,需要写一写特殊代码来进一步处理HTTP请求的参数。仅从这样一个简单例程就能看出页模式没有程序模式那么自动化,不过,页模式更灵活。尤其值得说的是,页模式给WebBroker和WebSnap程序增加了可视化设计的能力。
控制布局
例程CgiIntra还展示了另外一个非常有趣的IntraWeb技术:基于HTML的布局控制(页模式整合WebBroker和布局控制没有什么关系,因为在程序模式中也有布局控制,我只是为了省事才用一个例程来说明这两种技术的)。程序编译后的结果页面就是在设计时放到窗体上的一系列组件的映射,可以通过修改组件属性改变页面外观。一个页面上有很多内容,如文本框、按钮和图片等,这些内容如何分布,如何控制尺寸和位置?
解决的办法是使用IntraWeb的布局管理器。在IntraWeb程序中,总是要用到布局管理器。默认的布局管理器是IWLayoutMgrForm,另外两个是IWTemplateProcessorHTML和IWLayoutMgrHTML,前者使用外部的HTML模版文件,后者内嵌HTML。
IWLayoutMgrHTML组件包括一个功能强大的HTML编辑器,在这里你可以像放置普通HTML元素那样嵌入IntraWeb组件(在外部HTML编辑器里,你必须手动实现)。此外,当你从编辑器中选择一个IntraWeb组件时(双击IWLayoutMgrHTML组件即可启动该编辑器),你可以使用对象观察器来修改组件属性。如图21.6,IntraWeb的HTML布局编辑器是一个工具强大的可视化HTML编辑器,产生的HTML代码可以在另外一页看到(Source页)。

图21.6: IntraWeb的 HTML 布局编辑器
在产生的HTML代码中,定义了页的结构。组件是通过特殊标记:大括号来标识的,如下:
<P> {%IWLabel1%} {%IWButton1%}</P>
提示:当你使用HTML时,组件就不使用绝对位置定位了,而是由HTML而定。因此,此时的窗体仅仅是个组件容器,因为窗体中组件的位置和大小被忽略了。
不管怎么说,布局管理器总是能够满足程序在浏览器中运行时的外观需求。

《Delphi从入门到精通》第21章 第三部分
Web 数据库应用程序
作为Delphi的组件库,IntraWeb的一个重要的特征就是支持数据库程序开发。IntraWeb应用程序向导允许创建带有数据模块的程序,这对于开发数据库应用程序来说是一个很好的起点。向导产生的代码为每一个会话期(session)产生一个数据模块的实例,并把其存入会话期数据。
下面是带有数据模块的IntraWeb程序的TuserSession类的代码:
type
TUserSession = class(TComponent)
public
DataModule1: TDataModule1;
constructor Create(AOwner: TComponent); override;
end;

constructor TUserSession.Create(AOwner: TComponent);
begin
inherited;
Datamodule1 := TDatamodule1.Create(AOwner);
end;
数据模块单元没有为数据模块分配全局变量,如果那样的话,整个数据模块将会被所有会话所共享,在多线程并发请求时将会有服务紊乱危机。然而,数据模块已经公开了一个同名的全局函数访问当前会话期的数据模块:
function DataModule1: TDataModule1;
begin
Result := TUserSession(RWebApplication.Data).Datamodule1;
end;
这意味着你可以这样访问数据模块:
DataModule1.SimpleDataSet1
不过实质上你访问的不是全局数据模块,而是使用当前会话期的数据模块。
第一个演示数据库的例程叫做IWScrollData,在数据模块上添加一个SimpleDataSet组件,在主窗体上添加一个IWDBGrid组件,属性设置如下:
object IWDBGrid1: TIWDBGrid
Anchors = [akLeft, akTop, akRight, akBottom]
BorderSize = 1
CellPadding = 0
CellSpacing = 0
Lines = tlRows
UseFrame = False
DataSource = DataSource1
FromStart = False
Options = [dgShowTitles]
RowAlternateColor = clSilver
RowLimit = 10
RowCurrentColor = clTeal
end
最重要的属性设置是去掉了控件的滚动条和边框(UseFrame属性),实际上,显示的数据已经确定了数据集的位置(FromStart属性)和显示在浏览器中的行数(RowLimit属性)。在用户界面,去掉了表格的竖线,相邻行用颜色交替区分。必须设置当前行的颜色(RowCurrentColor属性),否则交替颜色将会不起作用,因为不论什么位置当前行的颜色和背景相同(只要把RowCurrentColor设成clNone就明白了)。程序IWScrollData运行效果如图21.7。

图21.7: 例程IWScrollData中的数据感知表格
当窗体创建的时候,通过使用当前会话期的数据模块打开数据集:
procedure TformMain.IWAppFormCreate(Sender: TObject);
begin
DataSource1.DataSet.Open;
end;
另外一段例程相关代码在Button的Click事件里,是用来实现数据向前和向后翻页的。这是其中btnNext的代码,另外一段与此类似,在此省略:
procedure TformMain.btnNextClick(Sender: TObject);
var
i: Integer;
begin
nPos := nPos + 10;
if nPos > DataSource1.DataSet.RecordCount - 10 then
nPos := DataSource1.DataSet.RecordCount - 10;
DataSource1.DataSet.First;
for i := 0 to nPos do
DataSource1.DataSet.Next;
end;
链接到具体数据
例程IWScrollData的表格显示数据库中的一页,通过按钮来向前或向后翻页。IntraWeb的表格还可以使用边框和滚动条从而能够在用户的浏览器中指定区域内显示更多的数据。例程IWGridDemo就演示这一特性。
该例子还展示了表格另外一个功能强大的属性:表格的Columns。该属性可以调整表格的外观输出和指定列行为。例如,显示超链接或者处理单元格和标题单元格的单击事件等。在例程IWGridDemo中,列Last_Name中嵌入一个超链接,员工号作为参数传给超链接。见图21.8。
图 21.8: IWGridDemo 主窗体使用嵌入超链接的带边框的表格
清单21.1列出了表格的关键属性。值得特别注意的是Last name那一列,前面提到过,该列嵌入一个超链接(可以把单元格的文本变成超链接)。通过该方法,程序可以打开第二个窗口让用户编辑数据,代码如下:
procedure TGridForm.IWDBGrid1Columns1Click(ASender: TObject;
const AValue: String);
begin
with TRecordForm.Create (WebApplication) do
begin
StartID := AValue;
Show;
end;
end;

清单 21.1: 例程IWGridDemo 中表格的属性
object IWDBGrid1: TIWDBGrid
Anchors = [akLeft, akTop, akRight, akBottom]
UseFrame = True
UseWidth = True
Columns = <
item
Alignment = taLeftJustify
BGColor = clNone
DoSubmitValidation = True
Font.Color = clNone
Font.Enabled = True
Font.Size = 10
Font.Style = []
Header = False
Height = ‘0‘
VAlign = vaMiddle
Visible = True
Width = ‘0‘
Wrap = False
BlobCharLimit = 0
CompareHighlight = hcNone
DataField = ‘FIRST_NAME‘
Title.Alignment = taCenter
Title.BGColor = clNone
Title.DoSubmitValidation = True
Title.Font.Color = clNone
Title.Font.Enabled = True
Title.Font.Size = 10
Title.Font.Style = []
Title.Header = False
Title.Height = ‘0‘
Title.Text = ‘FIRST_NAME‘
Title.VAlign = vaMiddle
Title.Visible = True
Title.Width = ‘0‘
Title.Wrap = False
end
item
DataField = ‘LAST_NAME‘
LinkField = ‘EMP_NO‘
OnClick = IWDBGrid1Columns1Click
end
item
DataField = ‘HIRE_DATE‘
end
item
DataField = ‘JOB_CODE‘
end
item
DataField = ‘JOB_COUNTRY‘
end
item
DataField = ‘JOB_GRADE‘
end
item
DataField = ‘PHONE_EXT‘
end>
DataSource = DataSource1
Options = [dgShowTitles]
End
通过设置第二个窗体的StartID变量,可以正确地定位记录:
procedure TRecordForm.SetStartID(const Value: string);
begin
FStartID := Value;
DataSource1.DataSet.Locate(‘EMP_NO‘, Value, []);
end;
提示:例程中表格的columns属性还有一个OnTitleClick事件,可以通过它来给数据排序或者执行其他操作。
第二个窗体也和主窗体一样使用同一个数据模块。因此,数据库数据更新后,在表格中就能看到数据的变化(但是更新仅在内存中,因为程序没有调用ApplyUpdates函数)。第二个窗体使用了IntraWeb提供的几个编辑控件和数据导航控件,运行时窗体情况见图21.9。

图 21.9: 例程IWGridDemo 中第二个窗体允许用户编辑记录
客户端数据组件
IWDBGrid组件不论怎么使用,都会生成把数据嵌到表格的HTML代码。但这些代码在客户端不能工作,只能浏览。另外一个组件(或者说IntraWeb的一个组件集)能够让你实现在客户端处理数据库。数据以一定的格式送到客户端,JavaScript代码在浏览器中能够这样工作:产生数据表格,在表格上实现移动数据等操作,但却与服务器无任何关联。
IntraWeb有很多客户端数据库组件,但下面三个比较重要:
IWClientSideDataSet 在程序代码中通过设置它的ColumnNames和Data属性能够在内存中定义一个数据集。在更新前,可以对客户端数据进行编辑、排序、过滤、定义master-detail关系等操作。
IWClientSideDataSetDBLink 通过它的DataSource属性可以链接任何Delphi 的数据集。
IWDynGrid 是一个通过Data属性可以连接前面提到的两个组件之一的动态表格。该组件可以把数据全部送到浏览器端,并通过JavaScript在客户端实现各种操作。

IntraWeb还有其他客户端组件,如IWCSLabel、IWCSNavigator和IWDynamicChart(仅适用于IE)。演示客户端数据组件的例程叫做IWClientGrid。程序代码很少,因为组件本身做了很多事情。下面是窗体的核心元素:
object formMain: TformMain
SupportedBrowsers = [brIE, brNetscape6]
OnCreate = IWAppFormCreate
object IWDynGrid1: TIWDynGrid
Align = alClient
Data = IWClientSideDatasetDBLink1
end
object DataSource1: TDataSource
Left = 72
Top = 88
end
object IWClientSideDatasetDBLink1: TIWClientSideDatasetDBLink
DataSource = DataSource1
end
end
窗体创建的时候,表格的通过DataSource就连接到了数据模块的数据集。程序运行状态见图21.10,程序允许用户依据任何单元格排序(使用列标题右侧的小箭头)和依据字段的可能值进行数据集过滤。如图,可以依据员工的Last Name排序,按照国籍和工作等级进行过滤。

图21.10:例程 IWClientGrid 的表格不需要和服务器取得联系就可以实现数据库基本操作
这样的功能是完全可能的,因为JavaScript把数据移到了浏览器端。下面是嵌在页面HTML中的脚本代码片断:
<script language="Javascript1.2">
var IWDYNGRID1_TitleCaptions =
["EMP_NO","FIRST_NAME","LAST_NAME","PHONE_EXT",
"DEPT_NO","JOB_CODE","JOB_GRADE","JOB_COUNTRY"];
var IWDYNGRID1_CellValues = new Array();
IWDYNGRID1_CellValues[0] = [2,‘Robert‘,‘Nelson‘,‘332‘,‘600‘,‘VP‘,2,‘USA‘];
IWDYNGRID1_CellValues[1] = [4,‘Bruce‘,‘Young‘,‘233‘,‘621‘,‘Eng‘,2,‘USA‘];
IWDYNGRID1_CellValues[2] = [5,‘Kim‘,‘Lambert‘,‘22‘,‘130‘,‘Eng‘,2,‘USA‘];
IWDYNGRID1_CellValues[3] = [8,‘Leslie‘,‘Johnson‘,‘410‘,‘180‘,‘Mktg‘,3,‘USA‘];
IWDYNGRID1_CellValues[4] = [9,‘Phil‘,‘Forest‘,‘229‘,‘622‘,‘Mngr‘,3,‘USA‘];
提示:之所以使用JavaScript而不是XML,是因为只有IE浏览器能够支持XML数据安全。Mozilla和Netscape缺乏这样的特性,并且对XML支持得很有限。使用XML实现同样的功能,运行时的代价是很大的。
接下来是什么?
关于IntraWeb的特性的需要说的远不止这些,但我的目的是让读者评估一下这种技术从而确定在将来的项目中是否使用。IntraWeb功能如此强大,我认为,如果开发一个Web程序,完全有理由选择它而不是再去寻找其他开发工具。
在Delphi的附盘上(不是主CD),可以找到很多关于IntraWeb的文章。Delphi默认安装包括了IntraWeb的例程,其中有很多程序展示了组件库的大多数特性。可以到IntraWeb网站(www.atozedsoftware.com)上下载IntraWeb的升级版本或者寻找文章和例程。

译者的话:
其实,在书店里我早就见过了该书的中译本,我仅是在一个偶然的机会里从网上下载了该书的英文电子版。由于手头正做一个Web程序的项目,使用了IntraWeb技术,无奈相关资料太少,就频繁参阅该书,同时觉得像我一样囊中羞涩的Programing fun大有人在,就译了出来。跟中译本没法比的了,不过作个参考还是可以的(自我遮羞)。
等到手头的项目结束,我打算写一些经验性的东东,总结一下切身体会。不知道会不会有读者?

使用delphi+intraweb进行微信开发3—微信消息处理

在第二讲使用delphi+intraweb进行微信开发2—intraweb以.net方式发布(以asp.net mvc4模式部署)在IIS(.net虚拟主机)上 我们成功把iw应用部署在了云虚拟主机上...

使用delphi+intraweb进行微信开发1~4代码示例

前几讲重点阐述的是使用iw进行微信开发的技术难点及解决方法,提供的都是代码片段(微信消息加解密是完整代码),实际上我始终感觉按照教程实作是掌握一门技术的最重要的方法!不过对于刚刚接触这类开发的朋友来说...

使用delphi+intraweb进行微信开发1--微信平台接入

使用DelphiXE2和Intraweb14.0.50进行微信开发。

使用delphi+intraweb进行微信开发

  • 2017年12月02日 10:08
  • 101KB
  • 下载

Android开发之使用Web Service进行网络编程

Android应用通常都是运行在手机平台上,手机系统的硬件资源是有限的,不管是存储能力还是计算能力都有限,在Android系统上开发、运行一些单用户、小型应用是可能的, 但对于需要进行大量的数据处理、...

怎样用ASP和COM进行Web编程(PDF)

  • 2006年10月20日 14:57
  • 12.74MB
  • 下载

怎样用ASP和COM进行Web编程(pdf) (二)

  • 2007年07月16日 13:35
  • 5.23MB
  • 下载

C++进行CGI的WEB编程

什么是 CGI?     公共网关接口(CGI),是一套标准,定义了信息是如何在 Web 服务器和客户端脚本之间进行交换的。     CGI 规范目前是由 NCSA 维护的,NCSA 定义 CGI...
  • inrgihc
  • inrgihc
  • 2015年11月24日 10:15
  • 372

怎样用 ASP 和 COM 进行 Web 编程

  • 2006年02月23日 15:31
  • 5.74MB
  • 下载
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:使用IntraWeb进行Web编程
举报原因:
原因补充:

(最多只允许输入30个字)