Delphi面向物件的編程方法 |
|
conundrum
尊榮會員 發表:893 回覆:1272 積分:643 註冊:2004-01-06 發送簡訊給我 |
http://www.cnread.net/cnread1/dnwl/cxsj/delphi/jcjc/006.htm
第二章 Delphi面向物件的編程方法(一)
________________________________________
Delphi的編程語言是以Pascal為基礎的。Pascal語言具有可讀性好、編寫容易的特點,這使得它很適合作為基礎的開發語言。同時,使用編譯器創建的應用程式只生成單個可執行檔(.EXE),正是這種結合,使得Pascal成為Delphi這種先進開發環境的編程語言。
本章中,我們將討論Object Pascal的主要特點,並講解如何在事件處理過程和其他應用程式中,使用它來編制程式碼。本章將講解Delphi應用程式中最常用的Object Pascal語法,而不是Pascal語言的一切細節。如果您完全不熟悉Pascal編程,請參閱一些基礎的Pascal教程。如果您具有編程經驗,並能熟練地使用其他流行程式語言,您將在本章的Object Pascal中發現一些相同的概念。如果您已經熟悉了Borland Pascal,就可以快速流覽或跳過本章。
2.1 編寫Object Pascal程式碼
在前邊的章節中,我們通過常式,已經編寫了幾行簡單的代碼。在本章中,我們將從熟悉Pascal編程的角度,配合實例,講解Object Pascal編程的基本方法。
在編寫自己的Object Pascal程式時,要注意程式的可讀性。Pascal語言是英式結構語言,在程式中選擇合適的縮排、大小寫風格,並在需要時將程式碼分行,會使得程式碼能夠很容易地被自己和他人讀懂。一般的程式師都有這樣的體驗:如果不給程式加上適當的注解,一段時間後,自己也難以理清程式的流程。給程式及時地加上注釋是良好的編程習慣。Delphi的注釋需要加注在{}之間,編輯器會把它們處理成為空白。Delphi保留了Borland Pascal編輯器的風格,關鍵字採用黑體字,被注釋的部分會變暗,這使得編程風格良好,易讀易寫。
2.1.1 編寫賦值語句
在事件處理過程中,最常用到的工作就是把一個新值賦給一個屬性或變數。在設計用戶介面時,可以使用Object Inspector(Object Inspector)來改變其屬性;但有時需要在程式執行時改變屬性的值,而且有些屬性只能在執行時改變,這些屬性在Delphi的線上幫助的“Proprety”主題中被標為執行期屬性。進行這種改變,就必須使用賦值語句。
下文的賦值語句表徵一個OnClick事件。當按鈕按動後,將編輯框部件Edit1的Color屬性置為clRed:
procedure TForm1.Button1Click(Sender: TObject);
begin
Edit1.Color := clRed;
end;
當按動按鈕後賦值語句被執行,編輯框變成紅色。
在語句中,部件的名稱在屬性前,中間用“.”表示屬性的所屬關係。這樣就準確地指定了要將clRed值賦給哪一部件的哪一屬性。賦值號為“:=”,不論給屬性還是給變數賦值,都是將右邊的值賦給左邊的屬性或變數。
當將一個屬性值、變數、常量或文本資料賦給屬性或變數時,所賦值的類型和接受此值的屬性或變數的類型應相同或相容。一個屬性或變數的類型定義了此屬性或變數的可能值集合,也定義了程式碼可以執行的運算。在前邊的常式中,編輯框部件的Color屬性和clRed的類型都是TColor。可以在線上幫助中找到一個屬性的類型;另外一種方法是在Object Inspector中選定該屬性值段,並按下F1鍵,則類型將在屬性說明的結尾處列出,例如Color屬性列出下邊的語句:
Property Color : TColor;
有些屬性是唯讀(Read Only)的,它們只能被讀取,不能被改變。請查閱線上幫助,在Delphi中這些唯讀屬性都有注解。
2.1.2 識別字的說明與使用
識別字是Delphi應用程式中一些量的名稱,這些量包括變數(var)、常量(const)、類型(type)、過程(procedure)、方法(Method)及其他,Object Pascal 在應用識別字時,必須首先說明它們。Object Pascal是強類型語言,它的編譯器可以檢查確保賦給變數或屬性的值是正確的類型,以便於您改正錯誤。因為Object Pascal是編譯語言,所以Delphi的執行速度要比使用解釋語言快得多。在使用識別字前說明它們,可以減少程式錯誤並增加代碼的效率。
2.1.2.1 變數
變數是程式碼中代表一個記憶體位址的識別字,而此位址的記憶體內容在程式碼執行時可以被改變。在使用變數前必須對它進行說明,即對它進行命名,並說明它的類型。在所有變數說明以前加上保留字var。變數說明左邊是變數的名稱,右邊則是該變數的類型,中間用(:)隔開。
var
Value ,Sum : Integer;
Line : String;
在表單中加入一個名稱為Edit1的編輯框,再加入一個名稱(屬性Name)為Add的按鈕部件,並建立如下的事件處理過程:
procedure TForm1.addClick(Sender: TObject);
var
X , Y: Integer;
begin
X := 100;
Y := 20;
Edit1.Text := IntToStr(X + Y);
end;
在本例中,當按動ADD按鈕時,編輯框中顯示值120。在Object Pascal中,必須確保變數或屬性被賦予類型相同或相容的值。您可以嘗試將賦給X的值改為100.0,或去掉IntToStr函數,在編譯時會出現類型不匹配的錯誤,這也說明瞭Object Pascal強類型語言的特點。
2.1.2.2 預定義類型
Object Pascal有多個預定義的資料類型,您可以說明任何這些類型的變數:
整形:Integer的範圍是-32768到32767,占2位元組的記憶體;Shortint從-128到127,占1位元組記憶體;Longint從-2147443648到2147483647 占4位元組記憶體;Byte從0到255,占1位元組;Word從0到65535,占2位元組記憶體。它們都是沒有小數部分的數位元。
實型:Single可以包含7到8位元元有效小數部分,佔用4位元元組的記憶體;Double類可以包含15到16位元元有效小數部分,佔用8位元元組的記憶體;Extended類型包含19到20位元元有效小數部分,佔用10位元元組記憶體;Comp可以包含19到20位元元有效小數部分,佔用8位元元組記憶體。以上實數類型只有在8087/80287選項[N+]打開才可以使用。Real可以包含11到12位元元有效小數部分,佔用6位元元組記憶體。它只有在和以前Borland Pascal相容的情況下才使用,否則應使用Double或Extended。
布林型:Boolean,只包含true或False兩個值,佔用1位元組記憶體。
字元型:Char,一個ASCII字元;字串類型String一串最長可達255個ASCII字元。
指針型:Pointer,可以指向任何特定類型。
字串型:PChar,是一個指向以零結尾的字串的指標。
除了預定義類型外,Delphi還有自行定義的類型。上述常式的TColor就是這種類型。此外,用戶還可以定義自己的資料類型,這部分內容將在下文中詳細講述。
整型類別和實型類別都各有五種類型,同一類別中,所有的類型與其他同類別的都相容,您可以將一種類型的值賦給相同類別中不同類型的變數或屬性,而只需要這個值的範圍在被賦值的變數或屬性的可能值範圍內。例如,對於一個Shortint型的變數,可以接受在-128到127範圍內的任意整數,例如Shortint類型的7;您不能將300賦給它,因為300已經超出了Shortint的範圍了。將範圍檢查功能打開(選用Options|Project,並在Compiler Options Page中選擇Range Checking),將會檢查出一個範圍錯誤;如果Range Checking沒有被打開,那麼程式碼將可以執行,但被賦值的值將不是您期望的值。
在一些情況下,您可以進行不同類型的變數或屬性的賦值。一般來說,可以將一個較小範圍的值賦給一個較大範圍的值。例如,您可以將整型值10賦給一個接受實型值的Double屬性而使得值成為10.0,但如果將一個Double類型的值賦給整形變數,則會出現類型錯誤。如果您不清楚類型的相容性,可以參閱Delphi的線上幫助中“Type Compatibility and Assignment Compatibility”主題。
2.1.2.3 常量
常量在說明時就被賦予了一個值,在程式執行過程中是不可改變的。下面的例子說明瞭三個常量:
const
Pi = 3.14159;
Answer = 342;
ProductName = "Delphi";
象變數一樣,常量也有類型。不同的是,常量假設其類型就是常量說明中其所代表的值的類型。上文的三個常量的類型分別是real型、整形、字串型。常量用“= " 表示兩邊的值是相等的。
2.1.3 過程與函數
過程與函數是程式中執行特定工作的模組化部分。Delphi的運行庫包含許多過程與函數以供您的應用程式調用。您不必瞭解過程與函數的邏輯,但要知道過程與函數的用途。在物件中說明的過程和函數稱為方法(Method)。所有的事件處理過程都是過程,以保留字procedure開頭。每一個事件處理過程只包含了當這一事件發生時需要執行的程式碼。在事件處理過程中使用Delphi已經存在的過程與函數,只需在程式碼中調用它們即可。
2.1.3.1 一個調用Delphi方法的簡單常式
下文將通過對一個Memo部件的文本進行剪切、拷貝、粘貼、清除等編輯的應用程式編制,介紹使用Delphi過程和函數的調用方法。
Memo(備註)部件有一個CutToClipboard方法,實現將用戶在memo中選擇的文本移到剪貼板上去。由於這個功能已經被建立在此方法中了,所以您只需知道這個方法做什麼以及如何使用它即可。
下面的語句表明如何調用一個名為Memo1的memo部件的CutToClipboard方法:
Memo1.CutToClipboard;
通過指定Memo1的名稱,說明調用哪一個部件的CutToClipboard方法。如果不指明物件名稱,Delphi會顯示Unknown identifier錯誤。當該事件處理過程被觸發,程式會執行CutToclipboard中的語句,將Memo1中的文本剪貼到剪貼板上去。
下文的常式展示了如何調用Delphi的方法,實現將備註部件的文本資訊剪切、拷貝到剪貼板上;將剪貼板上的標記文本粘貼到備註中,清除備註部件中的全部文本等四個功能。
打開一個新的空表單,加入一個memo部件和四個按鈕,並排列整齊。改變按鈕部件的Name屬性,分別命名為Cut,Copy,Paste,Clear。您會發現,當Name屬性發生改變時,Caption屬性將發生相應的變化。在Caption屬性前加標“&”號設立加速鍵
將memo部件的ScrollBars屬性設為ScVertical,以便加上滾行條。將WordWrap屬性設置為True,這樣當用戶輸入文本到達Memo部件的右邊緣時會自動回行。將Line屬性第一行的Memo1文本刪除,使得memo部件在初始顯示時為空的。
為每一個按鈕建立如下的事件處理過程:
procedure TForm1.CutClick(Sender: TObject);
begin
Memo1.CutToClipboard;
end;
procedure TForm1.CopyClick(Sender: TObject);
begin
Memo1.CopyToClipboard;
end;
procedure TForm1.PasteClick(Sender: TObject);
begin
Memo1.PasteFromClipboard;
end;
procedure TForm1.ClearClick(Sender: TObject);
begin
Memo1.clear;
end;
執行此程式。您可以在備註部件中輸入文本,在進行了文本的標記後,可以任意地進行剪切、拷貝、粘貼和清除。當按鈕被按動時,就調用相應的過程進行處理。用戶可以通過查閱線上幫助進行Memo部件的Topic Search,在Memo Component項中查閱Method,會得到以上過程的詳細說明。
2.1.3.2 調用Delphi的含參過程
有些過程要求用戶指明參數。被調用的過程會在執行時使用傳入的參數值,這些值在過程中被認為是已經被說明的變數。例如,LoadFromFile方法在TString物件中被說明為:
Procedure LoadFromFile(const FileName: String);
在調用這一過程時,應指明FileName參數是要裝入的檔案名稱。下麵的程式將先打開Open對話方塊,當您選擇了一個檔後,Delphi將把該檔讀入一個Memo部件:
begin
OpenDialog.Execute;
Memo1.lines.LoadFromFile(OpenDialog.FileName);
end;
2.1.3.3 使用Delphi函數
與過程一樣,函數的程式碼也執行特定的工作。它和過程的差別為:函數執行時會返回一個值,而過程則沒有返回值。函數可以用來賦給一個屬性或變數;也可以使用返回值來決定程式的流程。
前文中我們實際上已經接觸過了函數。在講述變數時,曾用到過下麵的程式段: Edit1.Text := IntToStr(X + Y);其中,IntToStr(Value)把一個LongInt類型的數值轉化為字串的值,Value是IntToStr唯一的參數,它可以是一個整形的值、變數、屬性或產生整形值的運算式。調用函數,必須把返回值賦給和此返回值類型相容的變數或屬性。
有些函數返回一個True或False的布林量,用戶的程式可以根據返回值來決定跳轉。下文的常式講述了函數返回值為Boolean的判斷用法:
在表單中加入一個ColorDialog物件和一個Name屬性為ChangeColor的按鈕。為按鈕的OnClick事件建立事件處理過程如下:
procedure TForm1.ChangeColorClick(Sender: TObject);
begin
if ColorDialog1.Execute then
Form1.Color := ColorDialog1.Color
else
Form1.Color := clRed;
end;
此事件處理過程使用一個返回Boolean值的Execute方法。按動按鈕,並在顏色對話方塊中選擇一個顏色。如果按動OK按鈕,ColorDialog.Execute方法將返回True,則Form1.Color將被賦值為ColorDialog1.Color,表單顯現您選用的顏色;如果按動顏色對話方塊的Cancel按鈕,方法將返回False值,表單將變為紅色。 http://www.cnread.net/cnread1/dnwl/cxsj/delphi/jcjc/007.htm
第二章 Delphi面向物件的編程方法(二)
________________________________________
2.1.4 跳轉語句
Object Pascal的跳轉語句有if和case兩個。
2.1.4.1 if語句
if語句會計算一個運算式,並根據計算結果決定程式流程。在上文的常式中,根據ColorDialog.Execute的返回值,決定表單的背景顏色。if保留字後跟隨一個生成Boolean值True或False的運算式。一般用“=”作為關係運算符,比較產生一個布林型值。當運算式為True時,執行then後的語句。否則執行else後的代碼,if語句也可以不含else部分,運算式為False時自動跳到下一行程式。
if語句可以嵌套,當使用複合語句表達時,複合語句前後需加上begin…end。else保留字前不能加“;”,而且,編譯器會將else語句視為屬於最靠近的if語句。必要時,須使用begin…end保留字來強迫else部分屬於某一級的if語句。
2.1.4.2 case語句
case語句適用於被判斷的變數或屬性是整形、字元型、枚舉型或子界型時(LongInt除外)。用case語句進行邏輯跳轉比編寫複雜的if語句容易閱讀,而且程式碼整形較快。
下面的常式顯示一個使用case語句的表單:
建立如下的事件處理過程:
procedure TForm1.Button1Click(Sender: TObject);
var
Number : Integer;
begin
Number := StrToInt(Edit1.Text);
case Number of
1,3,5,7,9: Label2.Caption := '奇數';
0,2,4,6,8: Label2.Caption := '偶數';
10..100:
begin
Label2.Caption := '在10到100之間';
Form1.Color := clBlue;
end;
else
Label2.Caption := '大於100或為負數';
end;
end;
執行程式,當Edit1部件接受到一個值,並按動“OK”按鈕觸發程式後,Number便被賦值為用戶輸入的數值。case語句根據Number的值判斷該執行哪一條語句。象if語句一樣。case語句也有可選擇的else部分。case語句以end結尾。
2.1.5 迴圈語句
Object Pascal的迴圈語句有三種:repeat、while和for語句。
2.1.5.1 repeat語句
repeat語句會重複執行一行或一段語句直到某一狀態為真。語句以repeat開始,以until結束,其後跟隨被判斷的布林運算式。參閱以下的常式:
i := 0;
repeat
i := i+1;
Writen(i);
until i=10;
當此語句被執行時,表單的下方會出現1到10的數字。布林運算式 i=10 (注意,與其他語言不同的是,“=”是關係運算符,而不能進行賦值操作)直到repeat..until程式段的結尾才會被計算,這意味著repeat語句至少會被執行一次。
2.1.5.2 while語句
while語句和repeat語句的不同之處是,它的布林運算式在迴圈的開頭進行判斷。while保留字後面必須跟一個布林運算式。如果該運算式的結果為真,迴圈被執行,否則會退出迴圈,執行while語句後面的程式。
下面的常式達到和上面的repeat常式達到同樣的效果:
i := 0;
while i<10 do
begin
i := i 1;
writeln(i);
end;
2.1.5.3 for語句
for語句的程式碼會執行一定的次數。它需要一個迴圈變數來控制迴圈次數。您需要說明一個變數,它的類型可以是整形、布林型、字元型、枚舉型或子界型。
下面的程式段會顯示1到5的數位,i為控制變數:
var
i : integer;
for i := 1 to 5 do
writeln(i);
以上介紹了三種迴圈語句。如果您知道迴圈要執行多少次的話,可以使用for語句。for迴圈執行速度快,效率比較高。如果您不知道迴圈要執行多少次,但至少會執行一次的話,選用repeat..until語句比較合適;當您認為程式可能一次都不執行的話,最好選用while..do語句。
2.1.6 程式模組
程式模組在Object Pascal中是很重要的概念。它們提供了應用程式的結構,決定了變數、屬性值的範圍及程式執行的過程。它由兩個部分組成:可選擇的說明部分和語句部分。如果有說明部分,則必在語句部分之前。說明部分包括變數說明、常量說明、類型說明、標號說明、程式,函數,方法的說明等。語句部分敍述了可執行的邏輯行動。
在Delphi中,最常見的程式模組便是事件處理過程中的程式模組。下面的事件處理過程是含有變數說明部分的程式模組:
procedure TForm.Button1Click(Sender Tobject);
var {程式模組的說明部分}
Name : string;
begin {程式模組的語句部分}
Name := Edit1.Text;
Edit2.Text := 'Welcome to Delphi' Name;
end; {程式模組結束}
庫單元也是程式模組。庫單元的interface部分含有庫函數、類型、私有,公有域的說明,也可以含有常量、變數的說明。這一部分可以作為程式模組的說明部分。在庫單元的implementation部分中通常含有各種事件處理過程,它們可以視為模組的語句部分,是事件處理模組。庫單元模組結束於庫單元結束的end.處。
程式模組中可以包含其他的程式模組。上文庫單元模組中含有事件處理模組。而庫單元模組實際是在工程程式模組中。
所有的Delphi應用程式都有相同的基本結構。當程式逐漸複雜時,在程式中加入模組即可。例如在庫單元模組中加入事件處理模組,向工程中加入庫單元模組等。模組化編程使得程式結構良好,並且對資料具有保護作用。
2.1.7 關於作用範圍
2.1.7.1 識別字的作用範圍
一個變數、常量、方法、類型或其他識別字的範圍定義了這個識別字的活動區域。對於說明這個識別字的最小程式模組而言,此識別字是局部的。當您的應用程式在說明一個識別字的程式模組外執行時,該識別字就不在此範圍內。這意味著此時執行的程式無法訪問這個識別字,只有當程式再度進入說明這個識別字的程式模組時,才可以訪問它。
下面的示意圖表示一個含有兩個庫單元的工程,每個庫單元中又各有三個過程或事件處理過程。
2.1.7.2 訪問其他程式模組中的說明
您可以在當前的程式模組中訪問其他程式模組中的說明。例如您在庫單元中編寫一個事件處理過程來計算利率,則其他的庫單元可以訪問這個事件處理過程。要訪問不在當前庫單元中的說明,應在這個說明之前加上其他應用程式的名稱和一個點號(.)。例如,在庫單元Unit1中有事件處理過程CalculateInterest過程,現在您想在庫單元Unit2中調用這一過程,則可以在Unit2的uses子句中加入Unit1,並使用下面的說明:
Unit1.CalculateInterest(PrincipalInterestRate : Double);
應用程式的代碼不能在一個模組外訪問它說明的變數。事實上,當程式執行跳出一個模組後,這些變數就不存在於記憶體中了。這一點對於任何識別字都是一樣的,不管事件處理過程、過程、函數還是方法,都具有這一性質。這樣的識別字稱為局部變數。
2.1.7.3 按照作用範圍說明識別字
您可以在應用程式的不同地方說明一個識別字,而只需保證它們的有效範圍不同即可。編譯器會自動訪問最靠近當前範圍的識別字。
庫單元的總體變數一般可以說明在保留字implementation後面。例如,下面的常式實現將兩個編輯框中的整數相加,顯示在第三個編輯框中。用到了一個整形的總體變數Count:
…implememntation
var
Count : Integer;
procedure TForm1.AddClick(Sender:TObject);
var
FirstNumber,SecondNumber:Integer;
begin
Count := Count 1;
Counter.Text := IntToStr(Count);
FirstNumber := StrToInt(Edit1.Text);
SecondNumber := StrToInt(Edit2.Text);
Edit3.Text := IntToStr(FirstNumber SecondNumber);
end;
…
為了實現每按動一次按鈕Count增加一次,必須對全程變數Count進行初始化處理。在程式庫單元的結尾處,最後一個end.保留字之前,加入保留字initialization和初始化Count的代碼:
…
initialization
Count := 0;
這樣當事件處理過程AddClick被觸發時,Count就會被增加一次,以表徵計算次數。如果用面向物件編程,則Count可以說明成表單的一個域,這在下一節中將有講述。
2.1.8 編寫一個過程或函數
在您開發Delphi應用程式時,所需的大部分代碼都編寫在事件處理過程中,但有時仍然需要編寫不是事件處理過程的函數或過程。例如,您可以把在多個事件處理過程中用得到語句編寫成過程,然後任何事件處理過程、過程、函數都可以象調用已經存在的過程或函數一樣直接調用它。好處是您只需編寫一次代碼,而且程式碼會比較清楚。
2.1.8.1 一個自行編寫的函數常式
在上文兩個數相加的程式中,如果編輯框中無值,則會使得程式出錯中斷。為避免這種情況,編寫下麵的函數,檢查編輯框中是否有值,如無值,則提醒用戶輸入:
function NoValue(AnEditBox:TEdit):Boolean;
begin
if AnEditBox.Text='' then
begin
AnEditBox.Color := clRed;
AnEditBox.Text := '請輸入整數值';
Result := True;
end
else
begin
AnEditBox.Color := clWindow;
Result := False;
end;
end;
NoValue函數會檢查編輯框是否為空,如果是,編輯框顏色變紅,並提醒用戶輸入一個整數,然後函數返回真值;Result保留字在Delphi中用來專指函數返回值。在上文的常式中加入NoValue函數:
procedure TForm1.AddClick(Sender: TObject);
var
FirstNumber,SecondNumber : Integer;
begin
if NoValue(Edit1)or NoValue(Edit2) then
exit;
Count := Count 1;
Counter.Text := IntToStr(Count);
FirstNumber := StrToInt(Edit1.Text);
SecondNumber := StrToInt(Edit2.Text);
Edit3.Text := IntToStr(FirstNumber SecondNumber);
end;
如果其中的任何一個返回真值,則表示有編輯框空,會執行exit過程,使得當前的程式模組停止執行,並使得編輯框出現輸值提示。當新值被輸入後,再執行程式時,紅色提示被隱去,恢復正常的計算狀態。
2.1.8.2 過程和函數的標題
每一個過程或函數都以標題開始,其中包括過程或函數的名稱和它使用的參數。過程以保留字procedure開始,函數以保留字function開始。參數位於括弧裏面,每一個參數以分號分隔。例如:
procedure validateDate(Day : Integer; month : Integer; Year : Integer);
您也可以將相同類型的參數組合在一起,則上述過程頭寫作:
procedure ValidateDate(Day, Month, Year : Integer);
函數在標題中還多了一項:返回值的類型。下麵是一個返回值為Double型的函數標題:
function CalculateInterest(principal,InterestRate:Double):Double;
2.1.8.3 函數和過程中的類型說明
一個過程或函數程式模組也含有說明部分和語句部分。說明部分可以包括類型說明、變數說明、常量說明等。除了Object Pascal語言中已經定義的類型之外,Delphi的應用程式還可以建立新的資料類型。類型說明部分有保留字type開始。下面是一些類型的說明:
type
Tcount = Integer;
TPrimaryColor = (Red,Yellow,Blue);
TTestIndex = 1..100;
TTextValue = -99..99;
TTestList = array [TTestIndex] of TTestValue;
TCharVal = Ord('A')..Ord('Z') ;
Today = (Monday,Tuesday,Wednesday,Thursday,Friday,Saturday,
Sunday) ;
在類型識別字後面,用“=”號定義了新的類型。類型界定了變數的取值範圍,例如,TCount類型的變數必須是整形值;一個TPrimaryColor類型的變數只能是red、yellow或blue等等。每一個類型的名稱都是由字母T開始,這並非必須的,但它是Delphi的慣例,在區別類型名和識別字時非常有用。類型說明可以是局部的,也可以是全局的。如果您把它放在implementation後面,則表明對於庫單元來講,它是全局的,所有的事件處理過程和其他的過程、函數都可以調用它。如果類型是在過程中被說明的,則是局部的,離開這一過程,該類型將失效。
一般來講,在過程和函數中,任何類型說明都在變數說明之前,而任何變數說明都在常量之前。但是,只要遵從說明必須在過程與函數的標題之後,而且在程式碼之前,即是有效的。 第二章 Delphi面向物件的編程方法(三)
http://www.cnread.net/cnread1/dnwl/cxsj/delphi/jcjc/008.htm 2.1.8.4 過程和函數的語句部分
過程或函數的語句部分由begin開始,end結束。函數需要一個返回值。可以將返回值賦給函數名稱,也可以將返回值賦給Result變數。下麵的常式將返回值賦給函數名稱:
function CalculateInterest(Principal,InterestRate: Double):Double;
begin
CalculateInterest := Principal * InterestRate;
end;
將返回值賦給Result變數也是可以的,則上面的程式改為:
Result := Principal*InterestRate;
下面是這個函數的調用方法:
InterestEarned :=CalculateInterest(2000,0.012);
在Implementation後面的過程和函數,可以且只能被此庫單元的事件處理過程使用。要讓過程和函數可以被其他的程式庫單元使用,則需要將過程或函數的標題部分放在庫單元中的interface部分,而把含標題的整個過程或函數放在庫單元的inplementation部分,並在要訪問這個過程或函數的庫單元的uses子句中加入說明這個過程或函數的庫單元名稱。
2.1.8.5 函數的遞迴調用
在Object Pascal中,過程或函數必須先說明再調用。上文的NoValue函數必須在使用它的事件處理過程之前說明和執行,否則程式會報告一個未知識別字的錯誤。
以上規則在遞迴調用時是例外情況。所謂遞迴調用,是指函數A調用函數B,而函數B又調用函數A的情況。在遞迴調用中,函數要進行前置,即在函數或過程的標題部分最後加上保留字forword。下文的常式是一個遞迴調用的典型例子:
…
implementation
var
alpha:Integer;
procedure Test2(var A:Integer):forword;
{Test2被說明為前置過程}
procedure Test1(var A:Integer);
begin
A :=A-1;
if A>0 then
test2(A); {經前置說明,調用未執行的過程Test2}
writeln(A);
end;
procedure Test2(var A:Integer);{經前置說明的Test2的執行部分}
begin
A :=A div 2;
if A>0 rhen
test1(A); {在Test2中調用已執行的過程Test1}
end;
procedure TForm1.Button1Click(Sender:TObject);
begin
Alpha := 15; {給Alpha賦初值}
Test1(Alpha); { 第一次調用Test1,遞迴開始}
end;
按鈕的OnClick事件處理過程給Alpha賦初值,並實現先減1再除2的迴圈遞迴調用,直到Alpha小於0為止。
2.1.8.6 過程和函數的參數
當您的程式碼在調用一個過程或函數時,通常用參數傳遞資料到被調用的過程或函數中。最常用的參數有數值參數、變數參數和常量參數三種。
由被調用過程或函數定義的參數為形參,而由調用過程或函數指明的參數叫實參。在NoValue函數中,說明函數體中的AnEditBox是形參,而調用時在if NoValue(Edit1)…中,Edit1是實參。
數值參數在運行過程中只改變其形參的值,不改變其實參的值,即參數的值不能傳遞到過程的外面。試看下麵的常式:
procedure Calculate(CalNo:Integer);
begin
CalNo := CalNo*10;
end;
用以下常式調用Calculate函數:
…
Number := StrToInt(Edit1.Text);
Calculate(Number);
Edit2.Text := IntToStr(Number);
…
Number接受由編輯框1輸入的數值,經Calculate過程運算。它是一個數值型實參。在進入Calculate函數後,會把Number實參拷貝給形參CalNo,在過程中CalNo增大十倍,但並未傳遞出來,因此Number值並未改變,在編輯框2中顯示仍然是編輯框1中的輸入值。形參和實參佔用不同的記憶體位址,在過程或函數被調用時,將實參的值複製到形參佔用的記憶體中。因此出了過程或函數後,形參和實參的數值是不同的,但實參的值並不發生變化。
如果您想改變傳入的參數值,就需要使用變數參數,即在被調用程式的參數表中的形參前加上保留字var。例如:
procedure Calculate(var CalNo : Integer);
則CalNo並不在記憶體中佔據一個位置,而是指向實參Number。當一個變參被傳遞時,任何對形參所作的改變會反映到實參中。這是因為兩個參數指向同一個位址。將上一個常式中過程頭的形參CalNo前面加上var,再以同樣的程式調用它,則在第二個編輯框中會顯示計算的結果,把第一個編輯框中的數值放大十倍。這時形參CalNo和實參Number的值都是Nnmber初始值的10倍。
如果當過程或函數執行是要求不改變形參的值,最保險的辦法是使用常量參數。在參數表的參數名稱前加上保留字const可以使一個形參成為常量參數。使用常量參數代替數值參數可以保護您的參數,使您在不想改變參數值時不會意外地將新的值賦給這個參數。
2.1.9 定義新的資料類型
Object Pascal有一些系統預定義的資料類型,在2.1.2中已經對它們作了介紹。您可以利用這些資料類型以建立新的資料類型來滿足程式的特定需要。下面簡單地敍述了您能建立的主要資料類型,如枚舉型、子界型、陣列型、集合型、記錄型、物件型等。
2.1.9.1 枚舉類型
一個枚舉型的說明列出了所有這種類型可以包括的值:
type
Tdays=( Sunday ,Monday,Tuesday,Wednesday,Thursday,Friday,Saturday);
可以定義上述枚舉類型的變數:
var
DayOfWeek:TDays;
在枚舉型中,括弧中的每一個值都有一個由說明它的位置決定的整形值。例如Sunday有整形值0,Monday有整形值1等。您可以把DayOfWeek說明為一個整形變數,並將一星期的每一天賦一個整形值以達到相同的效果,但用枚舉型會使得程式可讀性好,編寫容易。當您在枚舉型中列出值時,您同時說明瞭這個值是一個識別字。例如您的程式中如果已經含有TDays類型且說明瞭DayOfWeeks變數,則程式中便不能使用Monday變數,因為它已經被說明為識別字了。
2.1.9.2 子界類型
子界型是下列這些類型中某範圍內的值:整形、布林量、字元型或枚舉型。在您想限制一個變數的取值範圍時,子界型是非常有用的。
type
Thours = 0..23;
TValidLetter = 'A' .. 'F';
TDays = ( Sunday ,Monday,Tuesday,Wednesday,Thursday,
Friday,Saturday); {枚舉型}
TWorkDay = Monday..Friday; {一個TDays型的子界}
子界型限定了變數的可能取值範圍。當範圍檢查打開時,(在庫單元的Implementation後面有{$R*.DFM}字樣表示範圍檢查打開,否則您可以在Options|Project|Complier Options中選擇Range Cheking來打開範圍檢查),如果變數取到子界以外的值,會出現一個範圍檢查錯誤。
2.1.9.3 陣列類型
陣列是某種資料類型的有序組合,其中每一個元素的值由其相對位置來指定,您可以在陣列的某個位置上放置資料,並在需要時使用這些資料。下面的類型說明瞭一個Double型的陣列變數:
var
Check : array [1..10] of Double;
它表示Check指向一個含有10個Double型元素的資料串列,代表每一個元素的是1到10之間的數位元,稱為索引。陣列的每一項由陣列名稱稱加上[]中的索引來表示。Check包含10個變數,Check[1]表示第一個變數。您也可以把陣列定義成類型:
type
TCheck = array[1..10] of Double;
則變數說明改為:
var
Check :TCheck;
您可以通過給陣列賦值等方法來使用陣列。下面的語句將0.0賦給Check陣列中的所有元素:
for J := 1 to 10 do
Check[J] := 0.0;
陣列也可以是多維的,下面的類型定義了一個20行、20列的陣列。
type
Ttable = array[1..20,1..20] of Double;
var
table1:TTable;
想將這一表格的所有資料初始化為0.0,您可以使用for迴圈:
var
Col,Row:Integer;
…
for Col :=1 to 20 do
for Row := 1 to 20 do
Table1[Col,Row] := 0.0;
2.1.9.4 字串類型
字串類型事實上是一個一維的字元陣列。當您說明一個字串型的變數時,您應當指明這個字串的大小,下面是說明字串類型的例子:
type
MyString: string[15];
var
MyName: MyString;
則變數MyName被說明成為最多可以包含15個字元。如果您沒有說明字串的大小,Delphi會認為字串包含最大值255個字元。給字串賦值可以直接使用單引號括起的字串賦值:
MyName := 'Frank.Smith';
或MyName := '張明';
因為MyName是一個可以包含15個字元的MyString型變數,上文的兩個的變數都是有效的,一個漢字可以視作兩個字元。當您給字串型變數賦的值多於定義數值時,例如將MyName賦為‘FrankSmith.Franklin’,則Delphi只會接受前15個字元‘FrankSmith.Fran’。在記憶體中,字元串通常佔用比所說明的大小多一個位元組的空間,因為第一個位置是一個包含這個陣列大小的位元組。您可以使用索引值來訪問字串的字元,MyName[1]可以得到MyName的第一個字元'F'。
您可以使用Delphi豐富的運算符、過程和函數來處理字串型的變數和屬性。下面介紹幾個常用的運算符和Delphi過程或函數:
Concat和( )功能相同,都可以將多個字串組合在一起,建立一個較大的字串;Copy會返回一個字串中的子字串;Delete在一個字串中從一個指定位置起刪除一定數目的字元;Insert在一個字串中插入一個字串;Length返回字串的長度;Pos返回一個子字串在一個字串中的位置,即索引值。
2.1.9.5 集合類型
集合類型是一群相同類型元素的組合,這些類型必須是有限類型如整形、布林型、字元型、枚舉型和子界型。在檢查一個值是否屬於一個特定集合時,集合類型非常有用。下面的常式可以說明集合類型的用法:
在表單上加入一個編輯框和一個按鈕,清除編輯框中的文字,在其上加上Caption為“輸入母音”的標籤Label,並在編輯框的下方加入一個空的標籤,將按鈕的Default屬性改為True,建立按鈕的事件處理過程如下:
procedure TForm1.Button1Click(Sender:TObject);
type
Tvowels=set of Char;
var
Vowels:TVowels;
begin
Vowels := ['a','e','i','o','u'];
if Edit1.Text[1] in Vowels then
Lable2.Caption := '是母音';
else
Lable2.Caption := '請再試';
end;
執行這個程式,在編輯框中輸入字母,運算式Edit1.Text[1] in Vowels的結果是布林型的,in是運算符,用來判斷字母是否存在于集合中。輸入的判別結果會顯示在編輯框的下方。以上就用到了集合類型TVowels。
2.1.9.6 記錄類型
記錄是您的程式可以成組訪問的一群資料的集合。下面的常式說明瞭一個記錄類型的用法:
type
TEmployee=record
Name : string[20];
YearHired:1990..2000;
Salsry: Double;
Position: string[20];
end;
記錄包含可以保存資料的域,每一個域有一個資料類型。上文的記錄TEmployee類型就含有四個域。您可以用以下的方式說明記錄型的變數:
var
NewEmployee,PromotedEmployee:TEmployee;
用如下的方法可以訪問記錄的單域:
NewEmployee.Salary := 1000;
編寫如下的語句可以給整個記錄賦值:
with PromotedEmployee do
begin
Name :='';
YearHired := 1993;
Salary := 2000.00
Position := 'editor';
end;
您的程式可以將記錄當成單一實體來操作:
PromptEmployee := NewEmployee;
以上介紹了用戶常用的自定義類型。在Delphi的編程中,物件是非常重要的用戶自定義資料類型。象記錄一樣,物件是結構化的資料類型,它包含資料的域(Field),也包含作為方法的過程和函數。在Delphi中,當您向表單中加入一個部件,也就是向表單物件中加入了一個域;每一個部件也是物件,每當您建立一個事件處理過程使得部件可以響應一個事件時,您即自動地在表單中加入了一個方法。在本章第2節中,將詳細講述Delphi面向物件編程的方法和技巧。
2.1.10 Object Pascal的庫單元Unit
Units是常量、變數、資料類型、過程和函數的集合,而且能夠被多個應用程式所共用。Delphi已經擁有許多預定義的程式庫單元可供您建立您的程式庫單元使用。Delphi的Visual Component Library由多個程式庫單元組成,它們說明瞭物件、部件以供您的應用程式用來設計用戶介面。例如,當您在表單中加入一個Check Box時,Delphi自動在您的程式庫單元中加入了Stdctrls庫單元,因為TCheckBox部件是在StdCtrls庫單元中說明的。
當您設計您的表單時,Delphi自動建立一個和您的表單有關的庫單元。您的庫單元不必都和表單有關,也可以使用預定義的只包含數學運算函數的庫單元,或是自行編寫數學函數庫單元。在一個庫單元中所有的說明都相互有關係,例如,CDialogs程式庫單元包含了在您的應用程式中使用的普通對話方塊的所有說明。
2.1.10.1 Object Pascal程式庫單元的結構
不管一個庫單元是否和一個表單有關,庫單元的結構都是相同的。其結構如下:
unit <庫單元名稱>
interface
uses <選擇性的庫單元列表>
{公有說明}
implementation
uses <選擇性的庫單元列表>
{私有說明}
{過程和函數的執行部分}
initialization {選擇性的}
{選擇性的初始化程式}
end.
2.1.10.2 程式庫單元的介面部分
interface是庫單元的介面部分,它決定了本庫單元對其他任何庫單元或程式的可見(可訪問)部分。您可以在介面部分說明變數、常量、資料類型、過程和函數等等。Delphi在您設計表單的庫單元中,將表單資料類型、表單變數和事件處理過程都說明在這一部分。
interface標誌庫單元介面部分的開始。在interface中的說明對要使用這些說明的其他庫單元或應用程式是可見的。一個庫單元可以使用其他Unit的說明,只需要在uses子句中指明那些庫單元即可。例如,您在庫單元A中編寫程式碼,且您想調用UnitB於interface部分說明的程式。您可以把庫單元B的名稱加入到A的interface部分的uses子句中,則任何A中的程式都可以調用B中說明的程式。而且,如果B中interface部分的uses子句中出現C庫單元,儘管A中未曾出現C,A同樣可以調用B、C庫單元在interface中說明的程式。但如果B出現在A的interface部分的uses子句中,那麼庫單元A便不能出現在B的interface的uses子句中。因為這樣會產生對庫單元的迴圈訪問。當試圖編譯時,會產生出現錯誤資訊。
2.1.10.3 程式庫單元的實現部分
實現部分implementation中包含interface中說明的過程、函數、事件處理過程的具體實現程式碼。這一部分可以有自己的額外說明,但這些說明是私有的,外部程式不能調用這些說明。在interface中說明的函數實體必須在implementation部分出現,可以使用標題簡寫:只輸入procedure或function保留字,後面跟過程或函數的名稱即可,其後則是程式的實現部分了。如果您在implementation部分說明任何常式,其標題並未出現在interface部分,則必須寫全其標題部分。
在implementation部分的uses子句中指定的庫單元,只供給本庫單元的程式使用其interface中說明的程式。其他使用本庫單元的庫單元,不能訪問這些在implementation的udes子句中庫單元的說明,因為在implementation後進行的庫單元包含是私有的。所以上例中,如果C出現在B的implementation部分,則A不能使用C的公有部分,除非C出現在A的uses子句中。在implementation中出現的迴圈訪問是Delphi所允許的,如果A的implemetation的uses子句中出現B,則B的implementation部分也可以出現A。
2.1.10.4 程式庫單元的初始化部分
初始化當前庫單元所使用的資料,或是通過interface部分將資料提供給其他應用程式、庫單元使用時,您可以在庫單元中加入一個initialization部分,在庫單元的end前加上您的初始化語句。當一個應用程式使用
|
本站聲明 |
1. 本論壇為無營利行為之開放平台,所有文章都是由網友自行張貼,如牽涉到法律糾紛一切與本站無關。 2. 假如網友發表之內容涉及侵權,而損及您的利益,請立即通知版主刪除。 3. 請勿批評中華民國元首及政府或批評各政黨,是藍是綠本站無權干涉,但這裡不是政治性論壇! |