2012-11-30 11 views
8

Come una sorta di esercizio di autoapprendimento, ho creato un modulo che contiene sei pannelli in un rettangolo 2x3 e voglio che si alternino tra visibile e invisibile uno dopo l'altro. Sto cercando di farlo utilizzando un ciclo for di qualche tipo. Potrei, naturalmente, scrivere qualcosa di simile:Come posso fare riferimento a un controllo il cui nome è determinato in fase di runtime?

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

Ma questo richiede un bel po 'di battitura a macchina ed è abbastanza inefficiente quando decido lo voglio aspettare per 100 ms tra ogni passo. Ad esempio, dovrei quindi modificare tutti e sei i passaggi per attendere. Questo è fattibile per sei passi, ma forse un'altra volta voglio farlo centinaia di volte! Quindi penso che ci debba essere anche un modo per usare un ciclo for per questo, dove una variabile varia da 1 a 6 e viene usata nell'identificatore dell'oggetto. Quindi sarebbe qualcosa di simile:

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

Ora, questo ovviamente non funziona, ma spero che qualcuno qui mi può dire se questo è in realtà possibile e se sì, come. Forse posso usare una stringa come identificatore? La mia spiegazione è probabilmente piuttosto negativa perché non conosco tutti i termini tecnici, ma spero che il codice spieghi qualcosa.

+1

Il problema non è l'aiuto. Devi imparare le basi della programmazione, e in questo caso gli array. Non si formano identificatori come quello in fase di esecuzione in una lingua come Delphi. –

+2

La funzione di aiuto non è inutile, ma è solo aiuto non tutorial. –

+0

Non ti riferisci a _variable_, ti stai riferendo a un oggetto, in particolare a un componente, il cui nome viene determinato in fase di esecuzione.In un linguaggio compilato come Delphi, non è possibile farlo realmente con una variabile, come un intero, solo con componenti, controlli o altri oggetti che sono memorizzati in un elenco in cui è possibile cercarli per nome. – jachguate

risposta

14

È possibile eseguire il ciclo attraverso l'array Components del proprietario.

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; 

È inoltre possibile utilizzare il metodo FindComponent, se si desidera un tipo molto specifico di componenti per nome. Per esempio, se si dispone dei 6 pannelli, ei loro nomi sono Panel1, Panel2, e così via:

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

L'array Components non ha nulla a che fare con la parentela. Per una relazione genitore-figlio, utilizzare l'array Controlli. L'array Components si occupa della relazione di proprietà. –

+0

@Rob: certo, hai ragione. Ho misspoke. Lo correggerò. –

+1

Fornisco un +1 per il metodo FindComponent. Penso che questo sia un metodo che non tutti conoscono ed è esattamente ciò di cui hanno bisogno. Grazie Ken! – Asped

4

Uso FindComponent metodo 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

Grazie mille! Questo ha risolto il mio problema. Quindi, il 'è' nella riga 3 guarda solo che tipo di oggetto è pnl? –

+0

benvenuto, l'operatore "is" controlla se un oggetto è di tipo specifico. – Igor

+2

Mentre sembra che risolva il tuo problema, e sicuramente risponde alla domanda che hai posto, non porterà a un facile mantenimento e sviluppo del codice. –

6

Questa è una situazione in cui si desidera creare i controlli dinamicamente in fase di esecuzione anziché in fase di progettazione. Cercare di affrontare 6 diverse variabili sarà solo un mondo di dolore. E quando avrai bisogno della griglia per essere 3x4 piuttosto che 2x3, rimpiangeresti questa decisione ancora di più.

Quindi, iniziare con un modulo completamente vuoto. E aggiungere, nel codice, una matrice bidimensionale di pannelli:

private 
    FPanels: array of array of TPanel; 

Poi, nel costruttore del form, o un gestore di OnCreate evento, è possibile inizializzare l'array chiamando una funzione come questa:

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; 

E ora è possibile fare riferimento ai pannelli utilizzando le coordinate cartesiane anziché una matrice monodimensionale piatta. Naturalmente, puoi anche dichiarare abbastanza facilmente un array monodimensionale, se lo desideri.

L'idea chiave è che quando si crea un grande numero di controlli in un layout strutturato, è meglio abbandonare il designer e utilizzare il codice (loop e matrici).

+3

+1 Mi piace creare componenti al volo in questo caso. Il mio unico consiglio/preoccupazione è che tu usi le variabili locali di 'Left, Top, Width, Height' che sono chiamate proprio come alcune proprietà di' TMyForm'. In questi casi, utilizzo 'aLeft' o' LLeft' o semplicemente 'L, T, W, H: integer' per evitare qualsiasi confusione di scope. –

+0

@ArnaudBouchez Questa è una critica giusta. –

+0

Grazie, anche questo è molto utile :) –

Problemi correlati