2012-11-30 31 views
8

作爲一種自學習練習,我製作了一個包含6個面板的窗體,這個窗體在2x3矩形中,我希望它們能夠在可見和不可見之間切換。我試圖通過使用for循環來實現。當然,我可以寫這樣的:如何引用在運行時確定其名稱的控件?

Panel1.Visible := true; 
Panel1.Visible := false; 
Panel2.Visible := true; 
Panel2.Visible := false; 
Panel3.Visible := true; 
etc. etc. 

但這需要打字的相當多,是相當低效的,當我決定我希望它等待每個步驟之間100毫秒。例如,我將不得不編輯所有六個步驟來等待。這是可行的六步,但也許有一次我想做一百次!所以我認爲還必須有一種方法來使用for循環,其中變量從1到6變化,並用於對象標識符。所以它會是這樣的:

for variable := 1 to 6 do begin 
Panel + variable.Visible := true; 
Panel + variable.Visible := false; 
end; 

現在,這顯然是行不通的,但我希望這裏有人能告訴我,這其實是在可能的,如果是,怎麼樣。也許我可以使用字符串作爲標識符?我的解釋可能很糟糕,因爲我不知道所有的技術術語,但我希望代碼解釋一些東西。

+1

問題不在於幫助。你需要學習編程的基礎知識,在這種情況下是數組。在Delphi等語言中,您不會像運行時那樣形成標識符。 –

+2

幫助功能不是無用的,但它只是幫助不教程。 –

+0

你不是指_variable_,而是指一個Object,更具體地說是一個Component,它的名字在運行時決定。在像Delphi這樣的編譯語言中,你不能用像變量這樣的變量來做到這一點,只能通過存儲在列表中的組件,控件或其他對象來完成,你可以按名稱查找它們。 – jachguate

回答

14

您可以循環顯示面板的所有者的Components數組。

var 
    i: Integer; 
    TmpPanel: TPanel; 
begin 
    { This example loops through all of the components on the form, and toggles the 
    Visible property of each panel to the value that is opposite of what it has (IOW, 
    if it's True it's switched to False, if it's False it's switched to True). } 
    for i := 0 to ComponentCount - 1 do     
    if Components[i] is TPanel then      
    begin 
     TmpPanel := TPanel(Components[i]); 
     TmpPanel.Visible := not TmpPanel.Visible;  // Toggles between true and false 
    end; 
end; 

您還可以使用FindComponent方法,如果你想通過名稱非常具體類型的組件。舉例來說,如果你有6個面板,他們的名字是Panel1Panel2,等等:

var 
    i: Integer; 
    TmpPanel: TPanel; 
begin 
    for i := 1 to 6 do 
    begin 
    TmpPanel := FindComponent('Panel' + IntToStr(i)) as TPanel; 
    if TmpPanel <> nil then  // We found it 
     TmpPanel.Visible := not TmpPanel.Visible; 
    end; 
end; 
+1

Components組件與親子關係無關。對於父子關係,請使用Controls數組。 Components數組處理所有權關係。 –

+0

@Rob:當然,你是對的。我錯過了。我會糾正它。 –

+1

我給FindComponent方法+1。我認爲這是一種不是每個人都知道的方法,正是他們需要的。 Thx Ken! – Asped

4

使用FindComponent方法TComponent

for variable := 1 to 6 do begin 
    pnl := FindComponent('Panel' + IntToStr(variable)); 
    if pnl is TPanel then 
    begin 
     TPanel(pnl).Visible := true; 
     TPanel(pnl).Visible := false; 
    end; 
    end; 
+0

非常感謝!這解決了我的問題。所以,第3行中的'是'只是看着pnl是什麼樣的對象? –

+0

歡迎,「是」運算符檢查對象是否是特定類型。 – Igor

+2

雖然這看起來像修復了你的問題,並且它肯定回答了你問的問題,但它不會導致易於維護和開發代碼。 –

6

這是你想要的情況在運行時而不是在設計時動態地創建控件。試圖解決6個不同的變量將成爲一個痛苦的世界。而當你需要網格是3x4而不是2x3時,你會更加遺憾這個決定。

因此,從一個完全空白的表格開始。並添加,在代碼中,面板的二維數組:

private 
    FPanels: array of array of TPanel; 

然後,在窗體的構造,或OnCreate事件處理程序,您可以通過調用這樣的函數初始化數組:

procedure TMyForm.InitialisePanels(RowCount, ColCount: Integer); 
var 
    Row, Col: Integer; 
    aLeft, aTop, aWidth, aHeight: Integer; 
    Panel: TPanel; 
begin 
    SetLength(FPanels, RowCount, ColCount); 
    aTop := 0; 
    for Row := 0 to RowCount-1 do begin 
    aLeft := 0; 
    aHeight := (ClientHeight-aTop) div (RowCount-Row); 
    for Col := 0 to ColCount-1 do begin 
     Panel := TPanel.Create(Self); 
     FPanels[Row, Col] := Panel; 
     Panel.Parent := Self; 
     aWidth := (ClientWidth-aLeft) div (ColCount-Col); 
     Panel.SetBounds(aLeft, aTop, aWidth, aHeight); 
     inc(aLeft, aWidth); 
    end; 
    inc(aTop, aHeight); 
    end; 
end; 

現在,您可以使用笛卡爾座標而不是平面一維數組來引用您的面板。當然,如果你願意的話,你可以很容易地聲明一個扁平的一維數組。

關鍵的想法是,當您在結構化佈局中創建大量控件時,最好放棄設計器並使用代碼(循環和數組)。

+3

+1我喜歡在這種情況下即時創建組件。我唯一的建議/關注點是使用'Left,Top,Width,Height'局部變量,這些變量的命名方式與'TMyForm'屬性一樣。在這種情況下,我使用'aLeft'或'lLeft'或者'L,T,W,H:integer'來避免範圍混淆。 –

+0

@ArnaudBouchez這是公平的批評。 –

+0

謝謝,這個也很有用:) –

相關問題