◆◆◆◆◆IntraWeb学习笔记◆◆◆◆◆希望与大家共同学习、提高 (100分)

  • 主题发起人 主题发起人 abc_xp
  • 开始时间 开始时间
http://forum.vclxx.org/forum.asp?FORUM_ID=40&CAT_ID=7&Forum_Title=%A7%F5%BA%FB%C5%AA%AA%CC%B1M%B0%CF
 
http://www.tmssoftware.com/有,但谁有非试用版 TMS IntraWeb Component Pack Pro
 
哪位兄弟可以访问这个网址
http://home.pchome.com.tw/guide/code6421/WSChart.htm
,这是code6421写的关于IntraWeb的文章
,我这里不能访问啊,多谢啦,可以地话,把它贴过来
 


淺談Interface
Write By code6421
多重繼承
OOP 的重點在於繼承,封裝,多型等概念上,其中以繼承最受爭議,尤其是多重繼承與單一繼承,到目前為止,
至少在實作上許多語言都選擇了單一繼承,原因不外乎多重繼承會將整個物件架構複雜化,為了保留多重繼承的特性,
Interface(介面) 的概念就成為最好的選擇,標準的OO 繼承課題就是父母與子女之間的關係,子女繼承了父與母的的特性,
此為多重繼承,但我們都知道,現實上子女並不會擁有父母的所有特性及能力,但在多重繼承概念上,子可以向上轉型為父,
也可以向上轉型為母,而這就是多重繼承受爭議的地方.
圖:多重繼承


由上面的圖我們可以發現,子同時繼承了父與母兩個類別,也就是說子擁有了父與母類別所有的
特性,讓我們以一個較簡單的方式來說,當父類別擁有抽煙的特性,那在多重繼承的觀念下
,子類別必然也有抽煙的特性,但我們都知道這並不是絕對的.因此我們需要讓子類別選擇是否會抽煙,基於這個理由,
我們得把父類別的抽煙特性定義成可覆載,這樣子類別才能選擇是否會抽煙,
如果這類特性不多的話還好,但多的話就很煩人了,所以多重繼承下的結果,必定是很沉重的.

多重繼承的替代品 - Interface
Interface 以支援某種能力(或擁有某種能力) 為主體來取代多重繼承,以上面的類別來定義的話,就如下圖:
圖:以Interface 實作取代繼承


從上圖來看,你可以發現子直接繼承人類別,而不是繼承父或母,那子類別如何擁有父與母的特性呢? 例如子類別要擁有抽煙的能力?

上圖中我們稱之為子類別繼承了人類別並實作了抽煙這個介面,我們也可以說子是個人,擁有抽煙的能力,
這樣的做法是否比上面的多重繼承更符合現實呢? 呵,我把這個問題留給你,我可不想再一次陷入論戰中,
回到Interface,基本上Interface 也擁有了繼承特性,你可以繼承抽煙這個Interface,並加入新的特性
圖:Interface 繼承

ㄜ…我知道這不太雅,呵,你就將就一下吧 :)
因此我們重新定義一下父母子的關係
圖:實作繼承的Interface

Interface 繼承與Class 繼承是差不多的,只是Interface 繼承了定義而非實體

類別也可以實作多個Interface,例如下圖:



DELPHI(PASCAL) 與Interface
基本上DELPHI 支援Interface 操作,但在DELPHI 6 之前的操作較不直覺,因此容易造成DELPHI 對Interface 支援不足的假象,
慶幸的是在DELPHI 6 中這個問題已經被解決了,這也使得Interface 成為WebSnap 最重要的部份,同時也在VCL 中有相當重的戲份,
下面是你最常看到的Interface 運用:
IMyInterface=interface
['{FE5A34E5-21AB-4120-971B-FDC3241AD55D}']
function SayHello:string;
end;
TMyObject=class(TInterfacedObject,IMyInterface)
function SayHello:string;
end;
TForm1 = class(TForm)
Button1: TButton;
procedure Button1Click(Sender: TObject);
private
procedure do
SayHello(Intf:IMyInterface);
{ Private declarations }
public
{ Public declarations }
end;
var
Form1: TForm1;
implementation
{$R *.DFM}
function TMyObject.SayHello:string;
begin
Result:='Hello';
end;
procedure TForm1.DoSayHello(Intf:IMyInterface);
begin
ShowMessage(Intf.SayHello);
end;
procedure TForm1.Button1Click(Sender: TObject);
var
Obj:TMyObject;
Intf:IMyInterface;
begin
Obj:=TMyObject.Create;
Intf:=(Obj as IMyInterface);
do
SayHello(Intf);
end;
OK,我想這個範例大家都看過了,接下來我們變點不一樣的
type
IMyInterface=interface
['{FE5A34E5-21AB-4120-971B-FDC3241AD55D}']
function SayHello:string;
end;
TMyObject=class(TEdit,IMyInterface)
function SayHello:string;
end;
TForm1 = class(TForm)
Button1: TButton;
procedure Button1Click(Sender: TObject);
private
procedure do
SayHello(Intf:IMyInterface);
{ Private declarations }
public
{ Public declarations }
end;
var
Form1: TForm1;
implementation
{$R *.DFM}
function TMyObject.SayHello:string;
begin
Result:='Hello';
end;
procedure TForm1.DoSayHello(Intf:IMyInterface);
begin
ShowMessage(Intf.SayHello);
end;
procedure TForm1.Button1Click(Sender: TObject);
var
Obj:TMyObject;
Intf:IMyInterface;
begin
Obj:=TMyObject.Create(Self);
Intf:=(Obj as IMyInterface);
do
SayHello(Intf);
end;
嘿! 我可沒要你照著打哦,這樣是不會通過編譯的,你得變成這樣才行(在DELPHI 5).

procedure TForm1.Button1Click(Sender: TObject);
var
Obj:TMyObject;
Intf:IMyInterface;
begin
Obj:=TMyObject.Create(Self);
Obj.GetInterface(IMyInterface,Intf);
do
SayHello(Intf);
Obj.Free;
end;

GetInterface 是用來取得我們想要的Interface,基本上它會傳回一個Boolean 代表是否取得了Interface,
如果你在DELPHI 6 的話,之前未修改過的那一個版本就可以通過編譯器,所以啦,DELPHI 6 還是進步了.
其實在DELPHI 6 中正規的寫法是這樣

procedure TForm1.Button1Click(Sender: TObject);
var
Obj:TMyObject;
Intf:IMyInterface;
begin
Obj:=TMyObject.Create(Self);
if Supports(Obj,IMyInterface,Intf) then

do
SayHello(Intf);
Obj.Free;
end;


如果你在DELPHI 5 中這樣寫也可以,不過你會發現Supports 除了繼承至TinterfacedObject 之外的物件都會傳回False,
這是因為DELPHI 5 的的TComponent 並未實作Iunknown(至少在明定上沒有),但在DELPHI 6中,TComponent 實做了相當於Iunknown的Iinterface,
所以如果你想要在你的程式中完整運用Interface,建議你還是用DELPHI 6 會較為直覺.
用DELPHI 5 的話還可使用下面的方法來通過編譯器
TMyObject=class(TEdit,IMyInterface,IUnknown)

這樣你就可以使用as 來轉型,可是如果你要使用Supports 的話,Compiler 會丟出一個錯誤,因此還是使用GetInterface 來的方便一點!

實作多個Interface
做這件事是很簡單的,一個類別可以實做一個已上的Interface,這我想你一定早就知道了,
因此在這裡我提一下有關實作多個Interface 時的運用.

轉型規則
一個類別實作了一個已上的Interface 時,例如X類別實做了A,B,C 三個Interface,因此你可以透過X 取得 A,
同樣的,你也可以透過A 取得 B或透過A 取得C,這在COM 中有很詳細的定義:
Symmetric(對稱) 當你透過A 成功取得 B,那麼你也可以透過B 成功取得A
Transitive(遞移) 當你透過A 成功取得B,且透過B 成功取得C,那麼你也可以透過A 成功取得C.
Reflexive(反身) 使用A 查詢 A 必定是成功的.

Delegation(代理)
從DELPHI 4 開始,OO PASCAL 就支援Interface Delegation,這種技術使得實作Interface 變的更有彈性,你可以從下面的範例中看出端倪
unit Unit1;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, StdCtrls;
type
IMyInterface=interface
['{2E173B2D-6BE9-4519-8E5F-6DEF400335EC}']
function SayHello:string;
end;
IMyInterface2=interface
['{3FD6CFDF-E028-4FD6-9834-299404C15FFF}']
function SayHello2:string;
end;
TMyObject2=class(TInterfacedObject,IMyInterface2)
function SayHello2:string;
end;
TMyObject=class(TInterfacedObject,IMyInterface,IMyInterface2)
private
FDelgateObj:TMyObject2;
public
property DelgateObj:TMyObject2 read FDelgateObj implements IMyInterface2;
constructor Create;
function SayHello:string;
end;
TForm1 = class(TForm)
Button1: TButton;
procedure Button1Click(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
end;
var
Form1: TForm1;
implementation
{$R *.dfm}
constructor TMyObject.Create;
begin
FDelgateObj:=TMyObject2.Create;
end;
function TMyObject2.SayHello2:string;
begin
Result:='I am Object2';
end;
function TMyObject.SayHello:string;
begin
Result:='I am Object1';
end;
procedure TForm1.Button1Click(Sender: TObject);
var
MyObject:TMyObject;
Intf1:IMyInterface;
Intf2:IMyInterface2;
begin
MyObject:=TMyObject.Create;
if Supports(MyObject,IMyInterface,Intf1) then
ShowMessage(Intf1.SayHello);
if Supports(MyObject,IMyInterface2,Intf2) then
ShowMessage(Intf2.SayHello2);
end;
end.

重點就在籃色字及紅色字的部份,你可以發現我們的TMyObject實作了兩個Interface,但你在裡面卻只找到IMyInterface的定義,
這是因為我們運用了Delgation 將IMyInterface2 導向TMyObject2,而它正是實作IMyInterface2 的類別,這種技術使得主類別簡潔許多
,同時也帶出了另一種運用:
unit Unit1;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, StdCtrls;
type
IMyInterface=interface
['{2E173B2D-6BE9-4519-8E5F-6DEF400335EC}']
function SayHello:string;
end;
IMyInterface2=interface
['{3FD6CFDF-E028-4FD6-9834-299404C15FFF}']
function SayHello2:string;
end;
TMyObject2=class(TInterfacedObject,IMyInterface2)
function SayHello2:string;
end;
TMyObject=class(TInterfacedObject,IMyInterface,IMyInterface2)
private
FDelgateObj:IMyInterface2;
public
property DelgateObj:IMyInterface2 read FDelgateObj write FDelgateObj implements IMyInterface2;
constructor Create;
function SayHello:string;
end;
TForm1 = class(TForm)
Button1: TButton;
procedure Button1Click(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
end;
var
Form1: TForm1;
implementation
{$R *.dfm}
constructor TMyObject.Create;
begin
FDelgateObj:=Nil;
end;
function TMyObject2.SayHello2:string;
begin
Result:='I am Object2';
end;
function TMyObject.SayHello:string;
begin
Result:='I am Object1';
end;
procedure TForm1.Button1Click(Sender: TObject);
var
MyObject:TMyObject;
MyObject2:TMyObject2;
Intf1:IMyInterface;
Intf2:IMyInterface2;
begin
MyObject:=TMyObject.Create;
MyObject.FDelgateObj:=TMyObject2.Create;
if Supports(MyObject,IMyInterface,Intf1) then
ShowMessage(Intf1.SayHello);
if Supports(MyObject,IMyInterface2,Intf2) then
ShowMessage(Intf2.SayHello2);
end;
end.
上面這個範例告訴我們,我們可以指派任何實作了IMyInterface2物件給TmyObject,這就是上面所說的另一種運用.

Property In Interface
DELPHI 6 中的說明檔標示這個是新功能,但事實上,DELPHI 5 就有這個能力了,沒有DELPHI 4,所以不知道她有沒有,
基本上這是讓你可以在Interface 中宣告Property,我們用一個範例開始:
unit Unit1;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, StdCtrls;
type
IMyInterface=interface
['{2E173B2D-6BE9-4519-8E5F-6DEF400335EC}']
function GetSayHello:string;
property SayHello:string read GetSayHello;
end;

IMyInterface2=interface
['{3FD6CFDF-E028-4FD6-9834-299404C15FFF}']
function GetSayHello2:string;
property SayHello2:string read GetSayHello2;
end;
TMyObject2=class(TInterfacedObject,IMyInterface2)
function GetSayHello2:string;
end;
TMyObject=class(TInterfacedObject,IMyInterface,IMyInterface2)
private
FDelgateObj:IMyInterface2;
public
property DelgateObj:IMyInterface2 read FDelgateObj write FDelgateObj implements IMyInterface2;
constructor Create;
function GetSayHello:string;
end;
TForm1 = class(TForm)
Button1: TButton;
procedure Button1Click(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
end;
var
Form1: TForm1;
implementation
{$R *.dfm}
constructor TMyObject.Create;
begin
FDelgateObj:=Nil;
end;
function TMyObject2.GetSayHello2:string;
begin
Result:='I am Object2';
end;
function TMyObject.GetSayHello:string;
begin
Result:='I am Object1';
end;
procedure TForm1.Button1Click(Sender: TObject);
var
MyObject:TMyObject;
MyObject2:TMyObject2;
Intf1:IMyInterface;
Intf2:IMyInterface2;
begin
MyObject:=TMyObject.Create;
MyObject.FDelgateObj:=TMyObject2.Create;
if Supports(MyObject,IMyInterface,Intf1) then
ShowMessage(Intf1.SayHello);
if Supports(MyObject,IMyInterface2,Intf2) then
ShowMessage(Intf2.SayHello2);
end;
end.
我們在Interface 將SayHello,SayHello2 定義為property,而實作這兩個Interface 只需實作Get Method就可以了,
這是否使得Interface 的運用又更方便了呢?
DELPHI 6 的Interface 支援已經相當完備了,如果你正巧有DELPHI 6,也正巧要開發軟體,
使用Interface 將會使你的軟體有更高的延展性,當然! 好好規劃也是很重要的.

DELPHI 6 的Interface 與 Variant
DELPHI 6 支援Custom Variants,這是一個非常有用的特色,但它和Interface 有何關係呢?
答案並不在Custom Variants 身上,而是在DELPHI 6 重新實作Variants這件事上,因為這個動作,使得我們下面的程式得以正常運作:
procedure TForm1.Button1Click(Sender: TObject);
var
MyObject:TMyObject;
MyObject2:TMyObject2;
Intf1:IMyInterface;
Intf2:IMyInterface2;
V:Variant;
begin
MyObject:=TMyObject.Create;
MyObject.FDelgateObj:=TMyObject2.Create;
V:=(MyObject as IInterface);
if Supports(V,IMyInterface,Intf1) then
ShowMessage(Intf1.SayHello);
if Supports(V,IMyInterface2,Intf2) then
ShowMessage(Intf2.SayHello2);
end;
這段程式碼隱含著一個意義,就是你可以把任何物件轉成IInterface 塞進Variant 中,那對你有何幫助呢? 呵! 我不知道,你慢慢想吧!
給DELPHI 5 使用者
是的,上面所談的技巧大多可以用DELPHI 5 達到,只是你必須要做一些額外的工作,
例如你可以將Iunknown,Idispatch 指派給Variant 後傳遞,但傳送的如果是TComponent 呢?
你必需想辦法將Iunknown 對應到TComponent 上,這就是額外的工作,DELPHI 6 提供我們更直覺的方式,
或許這正是升級DELPH 6 的好藉口 :)

最後......................
文中的程式碼如果可以運作的話,那是我寫的,如果不能的話,那我不知道是誰寫的. :)

 
还有一些文章,都贴在这里太长了啊
 
编程技巧杂志也有黄忠诚的连载,讲interweb的
 
能在网上找到吗?
 
我有几个疑问
1。导航栏的问题,目前我的解决方法和demo里一样,使用一个frame,在frame中use每个form的unit,然后在每个form中插入这个frame,但是这样做只能限于点击
frame上的链接来跳转页面。如果form1上有一个链接(不在frame上)连到form2,那么form1就要use form2的unit,同样如果form2要链到form1,也要use form1的unit,依此类推,如果很多form
之间要互相连接,而链接又不在frame上,应该怎么做?
2。用adoquery关联查询两个表,与之相连的iwdbgrid无法设置column的datefield,提示"Invalid field size"
 
to wangfu
编程技巧杂志有网址吗?
 
http://www.comprg.com.cn/
 
哪位兄弟有安装过5.0.55版本成功过地?
5.0.53安装注册运行都正常,5.0.55安装后编译正常,运行时提示'$+0' is not a valid integer value.有能解决的吗?
 
多人接受答案了。
 
IntraWeb确实是个好东东
 
to: abc_xp
<<2、看了HELP后发现,可以用模板,巨爽
<<在程序所在的目录建一个名为Templates的目录,里面放HTML模板。模板文件名必须与窗体名一样,
<<也就是说如果formMain窗体要使用模板地话,模板名必须为formMain.html。
<<formMain上有一名为EditName的TIWEdit组件,在模板的某上位置打入 {%EditName%},那么
<<<{%EditName%}所在的位置就是EditName显示的位置。
<<哈哈,这样你可以十分方便地定制网页的布局了。
我用7.0, 用你的办法,不行,为什么?
还有: http://localhost:8888/demo.exe/start
也不行,为什么?
 
1、注意要同名
2、EXE不行,必须编译成DLL,还要注意权限
如 http://localhost:8888/iw/demo.dll/start
IW要有“执行(包括脚本”的权限,可以为虚拟目录
另:start是否要加还要看你的设置
 
后退
顶部