自Delphi2以后,Chad Z. Hower就一直在為建立一種簡(jiǎn)化Web程序開(kāi)發(fā)的Delphi架構而努力,這種簡(jiǎn)化的核心思想就是使開(kāi)發(fā)Web程序像開(kāi)發(fā)普通窗口程序一樣簡(jiǎn)單并且可視化。一些程序員了解動(dòng)態(tài)HTML、JavaScript、 Cascading Style Sheets和最新的互聯(lián)網(wǎng)技術(shù);而另一些程序員則想像創(chuàng )建VCL和CLX應用程序那樣創(chuàng )建Web程序。
IntraWeb就是應第二種開(kāi)發(fā)者的需求而問(wèn)世的,她功能強大,即便是專(zhuān)業(yè)的Web程序員也能夠從中受益。用Chad的話(huà)來(lái)說(shuō),IntraWeb是用來(lái)開(kāi)發(fā)Web程序而不是用來(lái)創(chuàng )建網(wǎng)站的。此外,IntraWeb組件可用于特有的應用程序或者是WebBroker 和 WebSnap應用程序。
在本章我不能詳述IntraWeb的每一個(gè)細節,安裝后,在Delphi上分布于數個(gè)組件板共計50個(gè)組件之多,實(shí)在太大了。我計劃講解一下基礎內容,您可以有選擇地用于您手頭的項目或是那些項目中的部分內容。
提示:在Delphi7光盤(pán)中有IntraWeb的PDF版手冊。如果您找不到,可以到Atozed Software公司的網(wǎng)站上去下載。關(guān)于IntraWeb的技術(shù)支持,可以參考Borland的新聞組。
IntraWeb簡(jiǎn)介
IntraWeb是Atozed Software公司出品的組件庫。在Delphi7的專(zhuān)業(yè)版和企業(yè)版中有相應版本的IntraWeb。專(zhuān)業(yè)版的IntraWeb只能用于頁(yè)模式(Page mode),關(guān)于頁(yè)模式本章稍后將會(huì )提到。盡管Delphi7是Borland公司的第一版包含該組件集的集成開(kāi)發(fā)環(huán)境,但IntraWeb已經(jīng)發(fā)展有幾年了,受到了相當好的評價(jià)和支持,包括很多第三方組件開(kāi)發(fā)商。
提示:
盡管您不能得到核心源代碼(需購買(mǎi)),IntraWeb體系架構是完全開(kāi)放的。并且所有組件的源代碼隨意可得。雖然IntraWeb是Delphi標準安裝的一部分,但同樣適用于Kylix。只要小心編寫(xiě),IntraWeb程序完全可以實(shí)現跨平臺。
注:除了Delphi 和Kylix版外,IntraWeb還有C++ Builder和Java版。.Net版正在開(kāi)發(fā)中,將會(huì )隨Delphi for .Net(Delphi 8)一起發(fā)布。
如果您擁有正版Delphi7,你完全能夠收到一個(gè)重大的升級信息,并且可以升級到IntraWeb5.1企業(yè)版,包括升級文檔和技術(shù)支持。(目前版本為7.19——譯者)
正如前面所講,IntraWeb背后的思想是構建Web程序而不是網(wǎng)站。當您使用WebBroker和WebSnap時(shí),你以Web pages和Page Producers術(shù)語(yǔ)在思考,同時(shí)您的工作緊緊地和HTML層次的網(wǎng)頁(yè)制作聯(lián)系在一起。而用IntraWeb時(shí),您想的是組件、屬性和事件,就像是在Delphi中作可視開(kāi)發(fā)一樣。
比如,創(chuàng )建一個(gè)新的IntraWeb應用程序,選擇File ? New ? Other,在新項目對話(huà)框中移到IntraWeb頁(yè),然后選擇Stand Alone Application。在接下來(lái)的對話(huà)框中(此對話(huà)框是Delphi的而不是IntraWeb的向導)你可以選擇一個(gè)已經(jīng)存在的文件夾或是輸入一個(gè)新文件夾(系統會(huì )自動(dòng)創(chuàng )建,之所以在此提及,是因為該對話(huà)框不是很清楚)。最終的程序包含一個(gè)項目文件和兩個(gè)不同的單元(稍后我會(huì )講到它的結構)。
現在,讓我們創(chuàng )建一個(gè)例程(隨書(shū)源代碼中叫做IWSimpleApp),步驟如下:
1、 移到程序的主窗體,從組件板中的IW Standard頁(yè)中選擇一個(gè)按鈕,一個(gè)文本編輯框和一個(gè)列表框添加到窗體。注意不是組件板中Standard頁(yè)中的VCL組件,而是相應的IntraWeb組件:IWButton,IWEdit和IWListbox。
2、 像下面那樣調整它們的屬性:
object IWButton1: TIWButton
Caption = ‘Add Item‘endobject IWEdit1: TIWEdit
Text = ‘four‘endobject IWListbox1: TIWListbox
Items.Strings = (‘one‘
‘two‘
‘three‘)
end
3、 雙擊按鈕組件編寫(xiě)OnClick事件,代碼如下:
procedure TformMain.IWButton1Click(Sender: TObject);
begin IWListBox1.Items.Add (IWEdit1.Text);end;
如圖21.1所示的web程序(圖中所示的是多兩個(gè)按鈕的最終版本)能夠把文本添加到列表框,創(chuàng )建它僅需這幾步。當你運行該程序時(shí)需要注意的是你每次單擊按鈕,瀏覽器都會(huì )向程序發(fā)送一個(gè)新的請求,該請求將會(huì )驅動(dòng)Delphi事件句柄產(chǎn)生一個(gè)新的基于窗體上組件新?tīng)顟B(tài)的HTML頁(yè)。
當您執行該程序時(shí),您看不到程序輸出的瀏覽器,而是一個(gè)IntraWeb控制器窗口(見(jiàn)圖21.2)。一個(gè)stand-alone IntraWeb應用程序是一個(gè)HTTP服務(wù)器,這一點(diǎn)在下一部分里會(huì )有詳細的闡述。您所看到的這個(gè)窗口是由每個(gè)stand-alone IntraWeb應用程序的項目文件中默認創(chuàng )建的IWRun函數來(lái)調用管理的。您可以在該調試窗口中選擇一個(gè)瀏覽器,并通過(guò)它來(lái)運行程序,或者把URL拷貝到剪切板,然后粘貼到您的瀏覽器中。程序默認使用一個(gè)隨機端口,該端口每次執行都不相同,因此,每次執行時(shí)的URL都不同。您可以通過(guò)選擇服務(wù)器設計器(有點(diǎn)像數據模塊)設定port端口屬性來(lái)改變這種行為。在該例中我用的是8080(一個(gè)普通的HTTP端口),當然,其他值也可以。
IntraWeb程序的代碼主要在服務(wù)器端,但IntraWeb也能夠產(chǎn)生JavaScript來(lái)控制程序的一些特性,因此在客戶(hù)端也可以執行特別的代碼。您可以通過(guò)使用特別的客戶(hù)端組件或者寫(xiě)一些特別的JavaScript代碼來(lái)實(shí)現。作為一個(gè)比較,下面例程IWSimpleApp中的兩個(gè)按鈕通過(guò)不同的方法實(shí)現顯示一個(gè)消息框。
兩個(gè)按鈕中的IWButton2使用Delphi代碼利用服務(wù)器端事件來(lái)顯示一個(gè)消息框。
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;

這兩個(gè)按鈕中的第二個(gè)(IWButton3)使用了JavaScript,這是通過(guò)在按鈕的ScriptEvents屬性的屬性編輯器中正確地設置JavaScript事件句柄來(lái)實(shí)現在Delphi程序中嵌入JavaScript的。

IntraWeb事件腳本編輯器
看到了吧,創(chuàng )建一個(gè)IntraWeb應用程序就和創(chuàng )建一個(gè)基于窗體的Delphi應用程序一樣簡(jiǎn)單:在窗體上放置組件然后處理它們的事件。當然,效果是不同的,畢竟這樣的程序是運行在瀏覽器中。為了讓您明白到底是怎樣工作的,我們簡(jiǎn)要地看一下這個(gè)簡(jiǎn)單的程序背后。這樣做會(huì )幫助您理解設置組件屬性和使用組件編程的效果。
這是一個(gè)基于瀏覽器的程序,因此沒(méi)有什么比看一下程序送到瀏覽器的HTML代碼能更好地理解它工作機制的方式了。打開(kāi)IWSimpleApp程序源代碼頁(yè),會(huì )發(fā)現分成了三部分。第一部分是類(lèi)似下面的樣式列表:
.IWEDIT1CSS {position:absolute;left:40;top:40;z-index:100; font-style:normal;font-size:10pt;text-decoration:none;}IntraWeb使用樣式不僅能確定每個(gè)組件的外觀(guān),如字體和顏色,而且能夠確定組件的位置,默認方式是相對位置定位。每個(gè)樣式受組件的很多屬性影響,如果您有樣式表的知識,您可以簡(jiǎn)單地試驗一下;如果不熟悉樣式表,那就相信IntraWeb吧,它會(huì )把組件在web頁(yè)上繪制得很好。
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的描述。主要的腳本塊包含初使化代碼和組件的客戶(hù)端事件處理代碼,例如:
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產(chǎn)生的其他文件。這些文件有些是通用的,而有些是捆綁給特定的瀏覽器的:IntraWeb能夠探測出所用瀏覽器,從而返回不同的JavaScript代碼和基本JavaScript文件。
注意:因為不是所有瀏覽器都能識別JavaScript的,所以IntraWeb只支持部分瀏覽器。支持的瀏覽器有最新版的Microsoft Internet Explorer、Netscape Navigator和開(kāi)放源代碼的 Mozilla (我用的就是)。由于Opera支持JavaScript更有限,所以默認情況下如被識別,IntraWeb就會(huì )發(fā)出一個(gè)錯誤信息(依賴(lài)于controller的SupportBrowsers屬性)。Opera能夠和免費的Arcana組件一起使用,在IW 5.1版中被正式支持。記住瀏覽器可能會(huì )偽造身份:比如,Opera常常被認成IE。為使站點(diǎn)不受瀏覽器的限制,設置支持更多的瀏覽器,卻又可能會(huì )導致運行錯誤和矛盾。
第三部分HTML是定義頁(yè)面結構的。在Body標記內部是一個(gè)帶有將要執行的動(dòng)作的form標記(同一行):
<form onsubmit="return FormDefaultSubmit();" name="SubmitForm" action="/EXEC/3/DC323E01B09C83224E57E240" method="POST">form標記依附于指定的用戶(hù)界面組件,如按鈕和編輯框:
<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組件。不過(guò),URL在IntraWeb中是最重要的傳遞信息方式。在程序中URL類(lèi)似下面:
http://127.0.0.1:8080/EXEC/2/DC323E01B09C83224E57E240第一部分是IP地址和stand-alone IntraWeb應用程序端口(使用不同的體系結構將會(huì )不一樣), EXEC 命令后面是累計請求次數,后面是session ID。稍后我們會(huì )討論Session。但現在我們就可以說(shuō)IntraWeb使用URL記號代替cookies從而忽略瀏覽器的設置而使應用程序可用。如果你愿意,可以通過(guò)設置controller的TrackMode屬性,來(lái)使用cookies代替URL標記。
在演示如何使用Delphi7中其他IntraWeb組件之前,讓我們來(lái)討論一下IntraWeb的關(guān)鍵東西: Web開(kāi)發(fā)的不同開(kāi)發(fā)模式,即AppMode和PageMode。前者可以開(kāi)發(fā)成一個(gè)獨立運行的可執行程序,也可以開(kāi)發(fā)成ISAPI DLL,甚至Apache Modules。AppMode能夠真正展示IntraWeb的優(yōu)秀特征。而PageMode則是WebBroker或WebSnap程序的IntraWeb簡(jiǎn)版插件,可以開(kāi)發(fā)除可執行程序之外的任何程序,如ISAPI、Apache Module、CGI等。IntraWeb基于這兩種模式提供了三種不同但又有所交叉的體系結構:
Standalone Mode 提供了一個(gè)像第一個(gè)例程那樣的自己的Web Server。這一點(diǎn)對于調試來(lái)說(shuō)相當便利(你可以在開(kāi)發(fā)環(huán)境中直接運行并且可以隨處設置斷點(diǎn))。Standalone mode開(kāi)發(fā)的程序可以運行在內聯(lián)網(wǎng)(Intranets)并且讓用戶(hù)在自己的電腦上脫機使用Web 界面工作。如果帶參數 -install 運行stand-alone程序,程序將會(huì )以服務(wù)形式工作,不顯示對話(huà)框界面。Standalone mode提供開(kāi)發(fā)使用IntraWeb自身作為Web服務(wù)器的AppMode程序的一種方法。
Application Mode 能夠開(kāi)發(fā)商務(wù)web服務(wù),建立Apache module或是IIS動(dòng)態(tài)鏈接庫。Application mode具備包括會(huì )話(huà)期管理在內的IntraWeb全部特性,并且是開(kāi)發(fā)通過(guò)Web即可升級的網(wǎng)絡(luò )程序首選。準確地說(shuō),Application mode可以開(kāi)發(fā)成為stand-alone程序,ISAPI動(dòng)態(tài)鏈接庫,或是Apache modules。
Page Mode 提供一個(gè)整合IntraWeb頁(yè)面和WebBroker與WebSnap應用程序的方法。Page mode能夠向現有的程序或是基于其他技術(shù)的動(dòng)態(tài)交互站點(diǎn)注入IntraWeb特性,提供更好的交互手段。Page mode是在CGI程序中使用IntraWeb技術(shù)的唯一選擇,不過(guò),Page mode不具有會(huì )話(huà)期管理特性,而具備該特性的Stand-alone IntraWeb程序卻不支持Page mode。
本章后面的例子,為了追求簡(jiǎn)單和調試方便主要使用Stand alone模式。但同時(shí)也會(huì )涉及Page mode。
《Delphi從入門(mén)到精通》第21章 第二部分
創(chuàng )建IntraWeb應用程序
創(chuàng )建IntraWeb應用程序,有很多組件可用。不妨看一下Delphi組件板中的IW Standard頁(yè),會(huì )給您留下深刻的印象,從簡(jiǎn)單的按鈕、復選框、單選框、編輯框、列表框到迷人的樹(shù)形控件、菜單、計時(shí)器、表格和鏈接應有盡有。我不想舉例描述每個(gè)組件的用法,只想通過(guò)幾個(gè)例子,闡述IntraWeb的體系結構,當然順便也會(huì )介紹用到的組件。
我創(chuàng )建了一個(gè)例程(叫IWTree),演示了IntraWeb的菜單和樹(shù)形控件的用法,同時(shí)也說(shuō)明了如何動(dòng)態(tài)創(chuàng )建組件。IntraWeb菜單通過(guò)引入常規Delphi菜單內容來(lái)工作的,這很容易,只需簡(jiǎn)單地把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 endendobject IWMenu1: TIWMenu
AttachedMenu = MainMenu1 Orientation = iwOHorizontalend菜單項運行時(shí)處理OnClick事件,是以鏈接形式實(shí)現的??匆幌聢D21.3,這是展示菜單的例程的運行效果。例程中的另外一個(gè)組件是樹(shù)形控件,在例子中預置了很多節點(diǎn)。該組件通過(guò)很多JavaScript代碼來(lái)實(shí)現在瀏覽器中(不需要調用服務(wù)器代碼)直接控制樹(shù)形控件節點(diǎn)的展開(kāi)和收疊。同時(shí),菜單中還有控制樹(shù)形控件節點(diǎn)展開(kāi)和收疊以及控制字體大小的菜單項。下面列出其中兩個(gè)事件代碼:
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 演示菜單、樹(shù)形控件和動(dòng)態(tài)創(chuàng )建組件的例程
感謝IntraWeb提供了如同標準Delphi VCL組件的特性,使代碼易讀,也容易理解。
例程中的菜單有兩個(gè)子菜單稍微復雜一點(diǎn)。第一個(gè)是顯示應用程序ID,也就是程序執行時(shí)的會(huì )話(huà)期ID。該標志可以通過(guò)全局對象WebApplication的AppID屬性獲得。第二個(gè)子菜單是Tree Contents,它可以把樹(shù)形控件的一級節點(diǎn)標題和子節點(diǎn)數目清單列出。值得注意的是,這些信息顯示在一個(gè)運行時(shí)才創(chuàng )建的組件memo里(見(jiàn)圖21.3),這一點(diǎn)與在一個(gè)VCL應用程序里面做同樣的事情非常相似。
procedure TformTree.TreeContents1Click(Sender: TObject);
var i: Integer;begin with TIWMemo.Create(Self) dobegin
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,此外動(dòng)態(tài)創(chuàng )建的memo的alignment屬性被設為alBottom。作為替代方法,可以使用anchors(同樣VCL中也有):可以創(chuàng )建一個(gè)bottom-right按鈕,或者在頁(yè)面中間的組件,只需把組件的四個(gè)anchors全設為true。請看下面關(guān)于該技術(shù)的例程。開(kāi)發(fā)多頁(yè)面應用程序
目前所講的例程都只有一個(gè)頁(yè)面,下面我們來(lái)創(chuàng )建IntraWeb程序的第二個(gè)頁(yè)面。其實(shí),就是這種情況,IntraWeb開(kāi)發(fā)工具也與標準Delphi(或Kylix)十分相似,而與其他互聯(lián)網(wǎng)開(kāi)發(fā)工具十分不同。下面的例子可以通過(guò)IntraWeb向導自動(dòng)產(chǎn)生源代碼,接著(zhù)研究我們關(guān)心的這些代碼。
我們從頭看,例程IWTwoForms的主窗體演示了IntraWeb表格特性。這是一個(gè)強大的組件,她產(chǎn)生的HTML表格既可放入文本又可放入其他組件。在本例中,程序開(kāi)始運行時(shí),填充表格的內容(在主窗體的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 dobegin
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;上面這段代碼的運行結果見(jiàn)圖21.4,除了輸出外,還有幾件事值得注意。首先,表格使用了Delphi的anchors屬性(全設為false)來(lái)使表格始終處在頁(yè)面中間,即使用戶(hù)改變了瀏覽器窗口大小。其次,我在第三列中加入了一個(gè)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是通過(guò)JavaScript來(lái)激活鏈接的,而不是直接的超鏈接。由于IntraWeb允許客戶(hù)端所有動(dòng)作,比如確認、檢查和提交,而這些動(dòng)作都依賴(lài)于JavaScript。例如,如果你把一個(gè)組件的Required設成true,則該組件如果沒(méi)有任何數據就不能提交,此時(shí)如果提交將會(huì )看到一個(gè)JavaScript錯誤信息(使用組件的FriendlyName屬性來(lái)定制的消息框)。本例的核心特性是它顯示第二個(gè)頁(yè)面的能力。為了實(shí)現這一點(diǎn),首先需要給程序添加一個(gè)IntraWeb頁(yè),方法是單擊File->New->Other…,啟動(dòng)Delphi的New Items對話(huà)框,翻到IntraWeb頁(yè),選擇Application Form,單擊“Ok”按鈕完成添加工作。接著(zhù)向該窗體上放一些組件,然后在主窗口中放置一個(gè)按鈕或其他控件用來(lái)顯示第二個(gè)窗體:
procedure TformMain.btnShowGraphicClick(Sender: TObject);
begin anotherform := TAnotherForm.Create(WebApplication); anotherform.Show;end;即使程序調用了Show方法,也會(huì )被看成是調用了ShowModal。這是因為IntraWeb把頁(yè)面當成堆棧來(lái)處理。最后顯示的頁(yè)面在棧頂,同時(shí)顯示在瀏覽器上。如果關(guān)閉該頁(yè)(隱藏或銷(xiāo)毀),就會(huì )顯示該頁(yè)的前一頁(yè)。在本例中,第二頁(yè)的關(guān)閉是通過(guò)調用Release方法,該方法在VCL程序中是結束正在運行的窗體的恰當方法。你也可以隱藏第二個(gè)窗體然后再顯示它從而避免每次都重建窗體的實(shí)例。
警告:在例程中的主窗體上放置了一個(gè)Close按鈕,但該按鈕沒(méi)有調用Release方法,而是調用了WebApplication對象的Terminate方法。該方法可以傳遞輸出信息,如WebApplication.Terminate(‘goodbye’);例程中使用了另一種替換方法:TerminateAndRedirect。
現在已經(jīng)知道如何創(chuàng )建帶有兩個(gè)窗體的IntraWeb程序,接著(zhù)我們簡(jiǎn)要地考查一下IntraWeb是如何創(chuàng )建主窗體的。當創(chuàng )建一個(gè)新程序時(shí),在項目文件里有由IntraWeb向導產(chǎn)生的相關(guān)代碼:
begin IWRun(TFormMain, TIWServerController);這一行不同于Delphi的標準項目文件,因為它調用了一個(gè)全局函數而不是應用全局對象的方法。函數的兩個(gè)參數分別是主窗體的類(lèi)和IntraWeb控制器的類(lèi)。該控制器能夠處理會(huì )話(huà)期和許多特性,稍后就會(huì )介紹。
例程中的第二個(gè)窗體顯示了IntraWeb另外一個(gè)有趣的特性:圖形支持。該窗體有一個(gè)顯示雅典娜神像的圖形組件,這是通過(guò)把一個(gè)位圖裝載進(jìn)一個(gè)IWImage組件中實(shí)現的:Intraweb把這個(gè)位圖轉換成JPEG格式,并存到創(chuàng )建于程序所在文件夾內的cache文件夾中,然后再返回該JPEG文件的引用。其相應HTML代碼如下:
<img src="/cache/JPG1.tmp" name="IWIMAGE1" border="0" width="153" height="139"> 該例程使用的IntraWeb另外一個(gè)特性是用戶(hù)可以用鼠標點(diǎn)擊圖像,并通過(guò)運行服務(wù)器端代碼來(lái)實(shí)現修改圖像的功能。在本例中,修改的結果是畫(huà)綠色的小圓圈。
代碼如下:
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;警告:繪制操作是發(fā)生在位圖的畫(huà)布(canvas)上。不要使用Image組件的畫(huà)布(在VCL組件Image中是可以這樣做的),也不要使用JPEG圖像,否則不是沒(méi)有響應就是出運行錯誤。會(huì )話(huà)期管理
注:Session就是通話(huà)、話(huà)路。在打電話(huà)的時(shí)候,通常情況下每一對用戶(hù)擁有一個(gè)話(huà)路,否則就會(huì )“竄線(xiàn)”了。在本章中,Session就是指客戶(hù)端的一個(gè)用戶(hù)和服務(wù)器交互的話(huà)路,或者稱(chēng)為交互通道。由于其他書(shū)籍中把Session譯作“會(huì )話(huà)期”,這里沿用該譯法?!g者。
如果你有一些Web編程經(jīng)驗,就會(huì )知道會(huì )話(huà)期管理是一個(gè)復雜的話(huà)題。IntraWeb提供預定義的會(huì )話(huà)期管理并且簡(jiǎn)化使用會(huì )話(huà)期的方法。如果在一個(gè)指定的窗體中需要會(huì )話(huà)數據,需要做的是給該窗體加一個(gè)域。IntraWeb窗體和組件會(huì )為每一個(gè)會(huì )話(huà)期創(chuàng )建一個(gè)實(shí)例。比如,在例程IWSession中,我給窗體添加一個(gè)域叫做FormCount,為了對比,我又在全局單元里聲明一個(gè)全局變量GlobalCount,這個(gè)變量會(huì )被程序的所有實(shí)例所共享。
為了加強對會(huì )話(huà)數據的控制同時(shí)讓多個(gè)窗體共享它,可以定制TuserSession類(lèi),該類(lèi)是IntraWeb應用程序向導在ServerController單元中自動(dòng)產(chǎn)生的。在例程IWSession中,我是這樣定制的:
type TUserSession = class public UserCount: Integer; end;IntraWeb 為每個(gè)新的會(huì )話(huà)期創(chuàng )建對象的實(shí)例,參閱ServerController單元中TIWServerController類(lèi)的IWServerControllerBaseNewSession方法:
procedure TIWServerController.IWServerControllerBaseNewSession(
ASession: TIWApplication; var VMainForm: TIWAppForm);begin ASession.Data := TUserSession.Create;end;在代碼中,會(huì )話(huà)期對象可以通過(guò)訪(fǎng)問(wèn)RwebApplication這個(gè)全局變量的Data域來(lái)引用,這個(gè)變量通常用來(lái)訪(fǎng)問(wèn)當前用戶(hù)的會(huì )話(huà)期。
提示:RwebApplication是線(xiàn)程變量,在IWInit單元中定義。她提供了訪(fǎng)問(wèn)會(huì )話(huà)期數據的線(xiàn)程安全方法:在多線(xiàn)程環(huán)境下訪(fǎng)問(wèn)它需要倍加小心。該變量可以在窗體和控件之外使用(基于線(xiàn)程的),這就是為什么主要用在數據模塊、全局程序和非IntraWeb類(lèi)內的原因。
此外,默認的ServerController單元提供一個(gè)可用的輔助函數:
function UserSession: TUserSession;
begin Result := TUserSession(RWebApplication.Data);end;因為大多數代碼已經(jīng)自動(dòng)產(chǎn)生了,像下面從例程IWSession中提取的代碼那樣,只需給TuserSession類(lèi)添加數據,就可用通過(guò)UserSession函數簡(jiǎn)單地應用了。在例程中,單擊按鈕,程序會(huì )累加幾個(gè)計數器(一個(gè)全局變量,兩個(gè)會(huì )話(huà)期指定的)并通過(guò)標簽顯示它們的值:
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;注意,程序通過(guò)調用Windows的InterlockedIncrement來(lái)避免被多線(xiàn)程所共享的全局變量發(fā)生訪(fǎng)問(wèn)沖突。也可以通過(guò)使用critical section或者是TidThreadSafeInteger(見(jiàn)于IdThreadsafe單元)來(lái)避免這種情況。
圖21.5顯示了程序的輸出(通過(guò)兩個(gè)不同的瀏覽器創(chuàng )建兩個(gè)會(huì )話(huà)期),程序還有一個(gè)復選框,用來(lái)激活計時(shí)器。聽(tīng)起來(lái)挺不可思議的,但實(shí)際上在IntraWeb程序中,計時(shí)器就和Windows中的計時(shí)器一樣工作。當計時(shí)器的時(shí)間間隔到期時(shí),相應的代碼就會(huì )被執行。在網(wǎng)頁(yè)中,這意味著(zhù)觸發(fā)JavaScript代碼來(lái)刷新頁(yè)面:
IWTIMER1=setTimeout(‘SubmitClick("IWTIMER1","", false)‘,5000);

圖21.5、運行在兩個(gè)不同瀏覽器中的IWSession例程與WebBroker和WebSnap整合
到目前為止,只講了如何創(chuàng )建stand-alone模式的IntraWeb應用程序。當你需要開(kāi)發(fā)IIS或是Apache下的IntraWeb動(dòng)態(tài)鏈接庫時(shí),情形也基本一樣。但是,如果你想用IntraWeb技術(shù)來(lái)拓展已有的WebBroker(或是WebSnap)程序,情況就不一樣了。
兩種技術(shù)的橋梁是IWPageProducer組件。該組件像其他頁(yè)生成器組件一樣依附于WebBroker的action,同時(shí)可以使用一個(gè)特殊的事件來(lái)創(chuàng )建并獲得一個(gè)IntraWeb窗體:
procedure TWebModule1.IWPageProducer1GetForm(ASender: TIWPageProducer;
AWebApplication: TIWApplication; var VForm: TIWPageForm);begin VForm := TformMain.Create(AWebApplication);end;僅一行代碼,就能實(shí)現IntraWeb頁(yè)嵌入WebBroker程序,在例程CgiIntra中也是如此。IWModuleController對IntraWeb支持提供核心服務(wù)。每個(gè)IntraWeb項目都必須有這種組件才能正確地工作。
警告:Delphi7中發(fā)行的IntraWeb的IWModuleController組件和Delphi的Web App Debugger有沖突,但問(wèn)題已經(jīng)解決,可以免費更新。
這是例程的web module窗體摘要:
object WebModule1: TWebModule1
Actions = < item Default = True Name = ‘WebActionItem1‘ PathInfo = ‘/show‘ OnAction = WebModule1WebActionItem1Actionend
item
Name = ‘WebActionItem2‘ PathInfo = ‘/iwdemo‘ Producer = IWPageProducer1 end> object IWModuleController1: TIWModuleController object IWPageProducer1: TIWPageProducer OnGetForm = IWPageProducer1GetFormend
end因為這是一個(gè)頁(yè)模式的CGI程序,所以沒(méi)有會(huì )話(huà)期管理。此外,頁(yè)面的組件狀態(tài)不能像標準IntraWeb程序那樣通過(guò)事件處理來(lái)自動(dòng)更新。為了達到同樣的效果,需要寫(xiě)一寫(xiě)特殊代碼來(lái)進(jìn)一步處理HTTP請求的參數。僅從這樣一個(gè)簡(jiǎn)單例程就能看出頁(yè)模式?jīng)]有程序模式那么自動(dòng)化,不過(guò),頁(yè)模式更靈活。尤其值得說(shuō)的是,頁(yè)模式給WebBroker和WebSnap程序增加了可視化設計的能力。
控制布局
例程CgiIntra還展示了另外一個(gè)非常有趣的IntraWeb技術(shù):基于HTML的布局控制(頁(yè)模式整合WebBroker和布局控制沒(méi)有什么關(guān)系,因為在程序模式中也有布局控制,我只是為了省事才用一個(gè)例程來(lái)說(shuō)明這兩種技術(shù)的)。程序編譯后的結果頁(yè)面就是在設計時(shí)放到窗體上的一系列組件的映射,可以通過(guò)修改組件屬性改變頁(yè)面外觀(guān)。一個(gè)頁(yè)面上有很多內容,如文本框、按鈕和圖片等,這些內容如何分布,如何控制尺寸和位置?
解決的辦法是使用IntraWeb的布局管理器。在IntraWeb程序中,總是要用到布局管理器。默認的布局管理器是IWLayoutMgrForm,另外兩個(gè)是IWTemplateProcessorHTML和IWLayoutMgrHTML,前者使用外部的HTML模版文件,后者內嵌HTML。
IWLayoutMgrHTML組件包括一個(gè)功能強大的HTML編輯器,在這里你可以像放置普通HTML元素那樣嵌入IntraWeb組件(在外部HTML編輯器里,你必須手動(dòng)實(shí)現)。此外,當你從編輯器中選擇一個(gè)IntraWeb組件時(shí)(雙擊IWLayoutMgrHTML組件即可啟動(dòng)該編輯器),你可以使用對象觀(guān)察器來(lái)修改組件屬性。如圖21.6,IntraWeb的HTML布局編輯器是一個(gè)工具強大的可視化HTML編輯器,產(chǎn)生的HTML代碼可以在另外一頁(yè)看到(Source頁(yè))。

圖21.6: IntraWeb的 HTML 布局編輯器
在產(chǎn)生的HTML代碼中,定義了頁(yè)的結構。組件是通過(guò)特殊標記:大括號來(lái)標識的,如下:
<P> {%IWLabel1%} {%IWButton1%}</P>提示:當你使用HTML時(shí),組件就不使用絕對位置定位了,而是由HTML而定。因此,此時(shí)的窗體僅僅是個(gè)組件容器,因為窗體中組件的位置和大小被忽略了。
不管怎么說(shuō),布局管理器總是能夠滿(mǎn)足程序在瀏覽器中運行時(shí)的外觀(guān)需求。
聯(lián)系客服