2012-12-05 62 views
3

我使用的是Delphi 5,我在運行時創建了一些面板,然後在面板上創建按鈕,顯然在運行時也是如此。我需要這樣做,因爲我可能需要在未來動態創建更多面板/按鈕組合。德爾福 - 在運行時創建的引用組件

我可以做所有這些,但是我不知道如何引用我創建的面板,因爲我找不到訪問面板組件名稱的方法。在Internet上搜索我發現我可以使用FindComponent來按名稱查找面板組件,但我仍然不知道如何使用該名稱,因爲我無法使用字符串變量來引用它 - 例如, StringVar:= Panel.Name。我得到一個類型不匹配,TComponentName與String。

我在創建面板時爲每個面板創建了按鈕。簡化,它看起來像這樣:

With TypeQuery do begin // Create Panels 
    First; 
    While (not eof) do begin  // create the actual panel 
     panelno := FieldByName('Product_type_id').AsInteger; 
     pnl := Tpanel.Create(Self); 
     pnl.name := FieldByName('PanelName').AsString; 
     pnl.color := clInactiveCaption; 
     pnl.parent := MainForm; 
     pnl.width := 365; 
     pnl.Height := 551; 
     pnl.left := 434 
     pnl.top := 122; 
     pnl.caption := ''; 
     With ButtonQuery do begin 
     Close; 
     Parameters.parambyname('PanelID').Value := PanelNo; 
     Open; 
     First; 
     While (not eof) and (FieldByName('Product_type_id').AsInteger = PanelNo) do begin //put the buttons on it. 
      btnName := FieldByName('ButtonName').AsString; 
      BtnText := FieldByName('ButtonText').AsString; 
      BtnGroup := FieldByName('Product_Group_ID').AsString; 
      GrpColour := FieldByName('ButtonColour').AsString; 
      btn := TColorButton.Create(Self); 
      btn.Parent := pnl; 
      btn.Name := BtnName; 
      Btn.backcolor := HexToTColor(GrpColour); 
      btn.Font.Name := 'Arial Narrow'; 
      btn.Font.Style := [fsBold]; 
      btn.Font.Size := 10; 
      . . . 
     end; 
     . . . 
    end; 
    end; 

我讀過幾個論壇(包括這一個),沒有辦法通過名稱直接引用面板。我試過使用組件數組,但是我遇到了同樣的問題 - 我需要通過指定的組件名稱來引用組件。

好的,我不是一個槍程序員 - 我用Delphi多年來創建簡單的程序,但這個更復雜。我以前從未使用過運行時組件創建。

我可以使用FindComponent使面板可見或不可見嗎?如果是這樣,鑑於我在上面給你們展示的東西,你能給我採取嬰兒步驟的方法嗎?

在此先感謝...

+1

您可以將需要的組件添加到TList | Container ...然後使用您的列表容器訪問它們... – Whiler

+2

這不是論壇。 :) – jachguate

回答

9

我不知道你所說的意思: 「我不能使用一個字符串變量來引用它 - 比如STRINGVAR:= Panel.Name

試試這個:

procedure TForm1.FormCreate(Sender: TObject); 
var 
    p: TPanel; 
begin 
    p := TPanel.Create(Self); // create a TPanel at run-time 
    p.Name := 'MyPanel'; // set a unique name 
    p.Parent := Self; 
end; 

procedure TForm1.Button1Click(Sender: TObject); 
var 
    p: TPanel; 
    StringVar: string; 
begin 
    p := FindComponent('MyPanel') as TPanel; 
    if Assigned(p) then // p has reference to MyPanel 
    begin 
    // use that reference 
    p.Caption := 'Foo'; 
    StringVar := p.Name; 
    ShowMessage(StringVar); 
    end; 
end; 

還是我錯過了什麼?

+2

不,你沒有。它應該很明顯,但事實並非如此!非常感謝。 – Capfka

+0

我在其他面板內有一個面板,所以我用這種方法首先找到父面板,然後從父面板調用FindComponent函數,這是工作。謝謝。 – QMaster

6

你與變量名混爲一談的組件名稱。 Delphi IDE努力使這兩者保持一致,即IDE創建的組件,但它們不一定相同。您沒有變量名稱,因爲您正在動態創建組件,並且您不知道需要多少個變量。但是,您仍然可以控制組件名稱:只需指定組件的Name屬性,然後通過調用FindComponent,以與使用其他組件名稱相同的方式使用它。只要確保每個面板實例的名稱都是唯一的。

還要記住的方式來處理變量,當你不知道在編譯時你需要多少,是用陣列名單。您可以使用普通的舊數組,或者您可以使用更復雜的數據結構,如TComponentListTDictionary

最後,爲了更容易地指的是你要創建的面板上的控制,你可以用面板分配和使用來代替。您可以在IDE中直觀地設計一個TFrame併爲按鈕命名,並且在運行時,可以實例化框架類,並且它會自動爲您創建所有按鈕,就像實例化表單或數據模塊時一樣。您只需要爲新的框架對象命名,但該對象已經具有指向按鈕的命名字段。

+0

+1; TDictionary已經可以在D5上使用了嗎? – Whiler

+1

@Whiler,不,但我們並不需要針對每個可能的Delphi版本單獨提出問題和答案。不管版本如何,這都是同樣的問題。人們可以在他們閱讀這個答案時使用的版本中使用他們可以使用的任何類。此外,我沒有說它必然是現代Delphi版本中的'TDictionary'類;任何人都可以編寫一個類似字典的類並使用它來存儲對象引用。 –

+0

thx的解釋;) – Whiler

0

您可以將需要的組件添加到TList | Container ...然後,用你的列表|容器來訪問它們

var 
    slPanels: TStringList; 
... 


With TypeQuery do begin // Create Panels 
    First; 
    While (not eof) do begin  // create the actual panel 
     panelno := FieldByName('Product_type_id').AsInteger; 
     pnl := Tpanel.Create(Self); 
     pnl.name := FieldByName('PanelName').AsString; 
     slPanels.AddObject(FieldByName('PanelName').AsString, pnl); 

當你需要它:

TPanel(slPanels.Objects[slPanels.IndexOf(FieldByName('PanelName').AsString)]) ... 

我不喜歡上面的代碼(有更好的容器......但是這應該做的工作: o))

+2

爲什麼每個人都堅持創建一個單獨的列表?該表單已經有一個(在Components數組中),也許有兩個(Controls數組),父級有一個或兩個(在Components和Controls數組中)。你不需要另一個。如果您需要將它們分組,請使用命名約定或爲「標籤」屬性設置一個值。 –

+0

也許是因爲我可以用字符串而不是整數來訪問它? ; o) – Whiler

+0

當然...你的方式去做,節省內存......(你有影響delphi研發實現TagString屬性與FMX?))) – Whiler

1

應該不需要創建您創建的項目的輔助列表以顯示在tForm實例上。

據我所知,只要您創建一個使用窗體或地方自

pnl := Tpanel.Create(Self); 

的其他容器,你不需要採取銷燬,然後新PNL的照顧,因爲它是由處理的新面板包含「自我」組件。

這意味着應該有任何將持有父組件的子組件的構造。

我希望你會在父對象中找到ComponentCount或Components列表或FindComponent方法。 假設「自我」引用的對象是一個Tform。

for i := 0 to tForm(self).ComponentCount -1 do 
    if tForm(self).Components[i] is tPanel then 
     tPanel(tForm(self).Components[i]).Caption := intToStr(i) ; 

將更改應用程序中tPanel的所有標題。 爲了區分由代碼和設計器創建的面板,您可以使用每個創建的tPanel的TAG屬性並在上例中使用它。

+0

是的,謝謝,我一直在使用標籤來保持面板的「順序」,方法是根據數據表的特徵將數據分配給它們。 – Capfka