Dynamiczne tworzenie komponentów - niewidoczny przycisk

0

Witam.

Poznaje tajniki dynamicznego tworzenia komponentów i trafiłem na problem...

W ramach testów stworzyłem sobie formę z jednym panelem
1.jpg

W FormCreate wklepałem:

 procedure TForm1.FormCreate(Sender: TObject);
begin
  WITH TButton.Create(Self) DO    // TOWRZENIE PRZYCISKU NA ISTNIEJĄCYM PANELU
   begin
        Parent:=Panel1;
        Caption:='TEST_1';
        Left:=100;
        Top:=100;
        Width:=200;
        Height:=200;
        Name:='button_test_1';
        Visible:=true;
   end;

  WITH TPanel.Create(Self) DO     // TWORZENIE PANELU
   begin
        Parent:=Form1;
        Left:=0;
        Top:=0;
        Width:=400;
        Height:=400;
        Name:='PANEL';
        Caption:='';
        Color:=$0048BD63;
   end;

  WITH TButton.Create(Self) DO    // TOWRZENIE PRZYCISKU NA STWORZONYM PANELU
   begin
        Parent:=TPanel(FindComponent('PANEL'));
        Caption:='TEST_2';
        Left:=100;
        Top:=100;
        Width:=200;
        Height:=200;
        Name:='button_test_2';
        Visible:=true;
   end;
end;     

Z tego co rozumiem powinien się utworzyć button na istniejącym panelu (tak się dzieje), nowy panel (to też działa) oraz przycisk na nowym panelu (przycisk się tworzy ale jest nie widoczny - jak to zmienić?).

2.jpg

2

Jeżeli używasz with to musisz określić że FindComponent to metoda formy a nie Buttona

Parent:=TPanel(Form1.FindComponent('PANEL'));
0

@kAzek dziękuję :)
Genialne w swej prostocie - choć sam na to bym chyba nie wpadł :)

A powiedzcie mi jeszcze proszę w jaki sposób usunąć dany komponent (i wszystkie dla których jest on rodzicem) tak aby można było później utworzyć komponent o takiej samej nazwie.

Np do poprzedniego kodu dodalem :

TPanel(FindComponent('PANEL')).Parent:=Nil;      // usuwnaie 'PANEL'
  TPanel(FindComponent('PANEL')).Free;

  WITH TPanel.Create(Self) DO     // TWORZENIE PANELU
   begin
        Parent:=Form1;
        Left:=0;
        Top:=0;
        Width:=400;
        Height:=400;
        Name:='PANEL';
        Caption:='';
        Color:=$0048BD63;
   end;

  WITH TButton.Create(Self) DO    // TOWRZENIE PRZYCISKU NA STWORZONYM PANELU
   begin
        Parent:=TPanel(Form1.FindComponent('PANEL'));
        Caption:='TEST_2';
        Left:=100;
        Top:=100;
        Width:=200;
        Height:=200;
        Name:='button_test_2';
        Visible:=true;
   end;
             

Taka procedura powoduje błąd (duplicate name).

1
var com:TComponent;
com:=Form1.FindComponent('PANEL');
if com<>nil then com.Free;

Aczkolwiek wystarczy:

Form1.FindComponent('PANEL').Free;
0

Taki kod zwraca błąd: "Duplicate name: A component named "butto_test_2" already exists".
Wychodzi na to ze panel zostaje usunięty, ale button którego był on rodzicem już nie ...

procedure TForm1.FormCreate(Sender: TObject);
begin
  WITH TButton.Create(Self) DO    // TOWRZENIE PRZYCISKU NA ISTNIEJĄCYM PANELU
   begin
        Parent:=Panel1;
        Caption:='TEST_1';
        Left:=100;
        Top:=100;
        Width:=200;
        Height:=200;
        Name:='button_test_1';
        Visible:=true;
   end;

  WITH TPanel.Create(Self) DO     // TWORZENIE PANELU
   begin
        Parent:=Form1;
        Left:=0;
        Top:=0;
        Width:=400;
        Height:=400;
        Name:='PANEL';
        Caption:='';
        Color:=$0048BD63;
   end;

  WITH TButton.Create(Self) DO    // TOWRZENIE PRZYCISKU NA STWORZONYM PANELU
   begin
        Parent:=TPanel(Form1.FindComponent('PANEL'));
        Caption:='TEST_2';
        Left:=100;
        Top:=100;
        Width:=200;
        Height:=200;
        Name:='button_test_2';
        Visible:=true;
   end;

  Form1.FindComponent('PANEL').Free;

 WITH TPanel.Create(Self) DO     // TWORZENIE PANELU
   begin
        Parent:=Form1;
        Left:=0;
        Top:=0;
        Width:=400;
        Height:=400;
        Name:='PANEL';
        Caption:='';
        Color:=$0048BD63;
   end;

  WITH TButton.Create(Self) DO    // TOWRZENIE PRZYCISKU NA STWORZONYM PANELU
   begin
        Parent:=TPanel(Form1.FindComponent('PANEL'));
        Caption:='TEST_2';
        Left:=100;
        Top:=100;
        Width:=200;
        Height:=200;
        Name:='button_test_2';
        Visible:=true;
   end;
end;      
0

Przycisk zostanie usunięty również, tylko że nie tak od razu.

0

W jednym z postów zadałem pytanie:
A powiedzcie mi jeszcze proszę w jaki sposób usunąć dany komponent (i wszystkie dla których jest on rodzicem) tak aby można było później utworzyć komponent o takiej samej nazwie.

Z Tego co Ty @_13th_Dragon piszesz każdy komponent trzeba zwalniać osobno (oczywiście możemy robić jakieś pętle itp to oczywiste), a nie o to chodziło.

Mam rozumieć że nie ma sposobu aby usuwając dany komponent usunąć "z automatu" komponenty dla których jest on rodzicem ?

1
  WITH TButton.Create(TPanel(Form1.FindComponent('PANEL'))) DO    
  begin
        Parent:=TPanel(Form1.FindComponent('PANEL'));
        Caption:='TEST_2';
        Left:=100;
        Top:=100;
        Width:=200;
        Height:=200;
        Name:='button_test_2';
   end;
 
  Form1.FindComponent('PANEL').Free; // zrobi free dla button_test_2 również
2

@hipekk - nie miałbyś tylu problemów, gdybyś referencje do dynamicznie tworzonych komponentów zachowywał w zmiennych lub polach klasy formularza; A tak to konstruktor zarówno przycisku jak i panelu zwraca referencję, ale idzie ona w kosmos i już nie możesz się odnieść po ludzku do takiego komponentu - zostaje cudowne FindComponent...

Proponuję w polach klasy lub zmiennych przechowywać referencje do wszystkich tworzonych dynamicznie komponentów, rezygnując tym samym z instrukcji wiążącej With w wywołaniu konstruktorów klas; Dzięki temu nie dość, że z dowolnego miejsca modułu będziesz mógł dobrać się do komponentu bez kombinacji z jego szukaniem, to jeszcze będziesz mógł taką zmienną lub pole wykorzystać przy tworzeniu nowych komponentów (jako Parent lub Owner);

A FindComponent używaj tylko tam, gdzie nie masz możliwości dostania się do komponentu inaczej, jak przez jego odszukanie na podstawie identyfikatora.

0

@furious programming, gdyby udało mu się zrobić jak mówisz to dynamiczne tworzenie komponentów traci sens. Co innego jeżeli to będą nie będą zwykłe zmienne z klasy formularza lecz tablice.

0

Dla mnie, dynamiczne tworzenie komponentów przydaje się w nieco innych przypadkach:

  • gdy podczas działania programu tworzę i pokazuję je dynamicznie - referencje lądują w zmiennych lub macierzy, dlatego że przy ich usuwaniu (także podczas działania programu) nie muszę ich szukać (odwołuje się do macierzy),
  • gdy muszę stworzyć dziesiątki komponentów tej samej klasy - tworzę je w pętli, gdzie referencja do każdego tworzonego komponentu ląduje w przygotowanej macierzy, zwalniam tak samo w pętli,
  • gdy komponentów na formularzu robi się dużo i nie chcę wszystkich bez potrzeby tworzyć, a nieaktywnych ukrywać (tych, których nie muszę wyświetlać od razu, a służą jako komponenty dodatkowe, np. do jakiejś opcji);
    Dzięki temu raz, że oszczędzam pamięć, dwa - nie muszę ich szukać, bo mam zapisane referencje do ich klas;

Z kolei metodę FindComponent używam tylko i wyłącznie tam, gdzie nie mam dostępu do referencji komponentu - np. w cudzych oknach, gdzie wskaźnik do instancji klasy muszę pobrać na podstawie nazwy komponentu; Stosuję taką zasadę, że jeśli nie muszę szukać - nie szukam, przez to nie tracę czasu; Taka technika jeszcze mnie nie zawiodła i nigdy bałaganu w kodzie nie miałem.

1 użytkowników online, w tym zalogowanych: 0, gości: 1