程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> 更多編程語言 >> Delphi >> 在Delphi中巧改窗體文件實現控件數組

在Delphi中巧改窗體文件實現控件數組

編輯:Delphi

delphi 開發的應用中,每一個窗體都有一個對應的窗體文件(.dfm),用來記錄該窗體的屬性以及窗體上所有控件的屬性,以便在窗體關閉後能准確地重新生成窗體。幾乎所有的DELPHI參考書都沒有提到過該文件的具體情況,偶爾提到,也都泛泛而談,因為窗體文件是二進制文件,只有在DELPHI提供的編輯環境中才能看到它的本來面目,對其進行操作可能會出現不可預知的錯誤;而且在大多數情況下,確實沒有修改的必要。而本文談到的和窗體文件密切相關。

要利用窗體文件,首先必須了解該類型文件的結構。窗體文件的結構很簡單,朋友們可以生成一個窗體,隨便放上一些控件,存盤後打開Unit1.dfm文件,就可以看到窗體文件是由關鍵字"object"和"end"構成的代碼段,基本結構如下:

object 控件名 :類名
屬性1 =屬性值
屬性2 =屬性值

end

並且支持嵌套。Delphi在記錄控件屬性時,只記錄修改過的屬性,舉一個例子,比如對一個標簽控件(label1)的缺省描述如下:

object Label1: TLabel
Left = 256
Top = 80
Width = 32
Height = 13
Caption = Label1
End

記錄的五個屬性都是隨開發者拖放的位置和順序不同而變化的,其它屬性由於沒有修改過,都是缺省值,所以不必記錄。

窗體文件是有序的,它的有序性表現如下:

object 窗體名:Tform
窗體屬性1=屬性值
窗體屬性2=屬性值
     。。。 。。。
// 以下是TgraphControl類型的控件
object 控件名:類名
控件屬性1=屬性值
控件屬性2=屬性值
    。。。 。。。
end
object 控件名:類名
控件屬性1=屬性值
控件屬性2=屬性值
    。。。 。。。
end
    。。。 。。。
// 以下是TwinControl類型的控件
object 控件名:類名
控件屬性1=屬性值
控件屬性2=屬性值
     。。。 。。。
end
object 控件名:類名
控件屬性1=屬性值
控件屬性2=屬性值
     。。。 。。。
end
    。。。 。。。
// 以下是其它類型的控件
object 控件名:類名
控件屬性1=屬性值
控件屬性2=屬性值
     。。。 。。。
end
     。。。 。。。
        end

在同一種類型的控件中,各控件排列的先後順序和它被拖放到窗體上的先後順序相同。這個順序是可以人為修改的,我們正是通過修改這個順序,來實現控件的數組化。下面將詳細介紹。

熟悉VB的朋友肯定知道在VB中可以通過控件拷貝實現控件的數組化。而DELPHI中則沒有這種功能。Delphi中可以使用Comp nts, Controls兩個控件數組在一定程度上模擬控件的數組化,比如:

for I := 1 to ControlCount-1 do
   if (Controls[I] is Tlabel) then
  (Controls[I] as Tlabel).Caption := Test;

這段代碼的功能是將窗體上所有Label的Caption屬性設為Test;這是一種非常有用的方法,大家如果不太熟悉可以參考delphi幫助作進一步了解。這種方法有很多局限,最明顯的是我們並不知道Controls[i]或Components[i]到底代表哪一個控件,只能用遍歷的方法進行篩選,這不僅影響了程序執行的效率,也帶來編程上的繁瑣。

其實,Controls和Components中控件的排列順序和對應的窗體文件(.dfm)中控件描述代碼段的排列順序是相同的。前面我們談到窗體文件是可以進行適當修改的,也就是說,我們可以根據需要調整窗體文件中控件描述代碼段的排列順序,讓Controls和Components這兩個控件數組全在掌握之中,這樣我們就能清楚知道Controls[I]或Components[I]具體代表的是哪一個控件。下面舉例說明。

比如,我們想讓窗體Form1上的所有Tbutton灰化,最簡單的方法是一句一句的編寫代碼:

Button1.Enabled := False;
Button2.Enabled := False;
   … …

如果Tbutton數量很多,代碼就變得很冗長。於是我們采用一個循環來實現:

for I := 0 to ControlCount -1 do
   if Controls[I] is Tbutton Then
  (Controls[I] as Tbutton).Enabled := False;

現在我們有了更有效的方法,首先打開窗體文件(Form1.dfm),調整Tbutton的排列順序,讓所有Tbutton的代碼段(Object…end)都排在一起,然後數一下前面其它控件代碼段的個數,設為n,n-1就是第一個Button在Controls(Components)數組中的位置,這樣程序就很簡單:

for I:= n-1 to n-1+ButtonNum do
  (Controls[I] as Tbutton).Enabled := False;

代碼的效率和簡潔比以前有了很大提高。其中ButtonNum是Button的個數。

下一個例子更能體現利用這一規律的優越性。在編寫Socket通信程序的時候,我們通常需要將用戶輸入的信息按照一定的順序形成字符串,然後發送給服務器,服務器再根據事先約定的順序解包,提取出內容,進行入庫或其它操作。在形成字符串時,一般都是直接寫代碼,比如:

InfoS := ;//用於存放字符串。
if Edit1.Text $#@60; $#@62; then InfoS := InfoS + Edit1.Text
else begin
       Application.Message(請填寫必要信息);
       Exit;
     end;
if Edit2.Text $#@60; $#@62; then InfoS := InfoS + Edit2.Text
else begin
       Application.Message(請填寫必要信息);
       Exit;
      end;
……

如果錄入的項目多,這種方法會使代碼冗長不堪。現在我們可以先調整窗體文件中Edit框描述代碼段的順序,讓它們排列在一起,並確定第一個Edit框在Controls控件數組中的位置(方法入前),設為n-1(其中n表示排在Edit框前面的控件的描述代碼段個數),編寫如下代碼實現:

for I := n-1 to n-1+EditNum do
    if ((Controls[I] as TEdit).Text $#@60; $#@62; ) then
      InfoS := InfoS + (Controls[I] as Tedit).Text
Else begin
      Application.Message(請填寫必要信息);
     Exit;
    End;
其中EditNum表示Edit框的個數。

還有其它很多方面的應用,在這裡就不一一贅述了。這實際上就是徹底實現了控件的數組化,而且這個數組還可以包含不同類型的控件。

這裡有兩個問題需要注意:一是在調整控件描述代碼段順序時,一定要遵照文中提到的窗體文件的有序性規則,比如試圖將一個TButton控件的描述代碼放在一個TLabel控件的描述代碼前面是不可能的;另外請大家注意Controls和Components的區別,窗體文件中,控件間的父子關系可以通過縮進的格式很明顯的看出來,在計算控件在數組中的位置時,一定要考慮控件間的層次關系,如果使用Controls,就應該只對同級控件進行計數,如果是Components,則應包括所有的控件。

當然,這種方法也有它的弊端,首先需要調整窗體文件順序,其次程序的可讀性會受到影響,所以大家在使用這種方法時應多寫幫助。

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved