Destruktory i odwołanie do komponentow dynamicznych wewnątrz innych.

0

Witam

Problem dotyczy odniesienia się do obiektów dynamicznych stworzonych na innym obiekcie dynamicznym lub statycznie umieszczonym na formie.
Mam Panel1 na nim umieszczam Image korzystając z:

 
with TImage.Create(Panel1) do begin
...
name:='aa1';
OnClick:=Zdarzenie;
...
end;

wywołać zdarzenia, odnieść się do nich itd potrafię, natomiast mam kłopot z pracą na stworzonym image i tu moje pytanie jak odnieść się do obiektu? Jak stworzony image zwolnić korzystając z free?

2

Stwórz sobie zmienną globalną/pole klasy lub odwołuj się per FindComponent.

0

Jeżeli ma Panelu jest tylko jeden komponent nie ma problem można wykorzystać właściwość Tag i w ten sposób:

Panel1.Tag:= Integer(TImage.Create(Panel1));
  TImage(Panel1.Tag).Parent:= Panel1;
  TImage(Panel1.Tag).Picture.LoadFromFile('h:\test.bmp');

O zwolnienie się nie martw Panel jest właścicielem Image więc zadba o jego zwolnienie no chyba że z jakiegoś powodu chcesz go zwolnic wcześniej to teraz możesz normalnie odwoływać się do Image więc nie ma problemu.
Przy większej ilości komponentów można by stosować choćby record zawierający pointery komponentów ale to już by trochę komplikowało kod.

0

Problem dotyczy odniesienia się do obiektów dynamicznych stworzonych na innym obiekcie dynamicznym lub statycznie umieszczonym na formie.

Jest kilka różnych wyjść - możesz trzymać referencję do tych klas np. w tablicach lub pojedynczych zmiennych (czy polach klasy-rodzica), możesz odwoływac się dynamicznie np. tak jak pokazał @kAzek, możesz wyszukiwać komponenty po nazwie (metodą FindComponent z odpowiednim rzutowaniem), albo pozostawić je i nie zwalniać, czym zajmie się klasa-rodzic w swoim destruktorze; Ostatnia opcja jest o tyle niezalecana, że dobrą praktyką jest sprzątanie po sobie (co się samemu utworzyło należy samemu zwolnić).

0

Cała zabawa polega na tym, że jest więcej image'ów utworzonych na tym panelu. Ogólnie mam kłopot ze sposobem odwołania się do nich bo klasyczne

TImage(FindComponent('aa1')).Visible:=False;

nie działa podobnie nie potrafię korzystając z FindComponent usunąć obiektu. Zależy mi na tym, żeby nie tworzyć kolejnych tablic.

0

Czy masz określoną liczbę tych TImage na tym Panelu ?

0
adydan napisał(a):

Cała zabawa polega na tym, że jest więcej image'ów utworzonych na tym panelu. Ogólnie mam kłopot ze sposobem odwołania się do nich bo klasyczne

TImage(FindComponent('aa1')).Visible:=False;

nie działa podobnie nie potrafię korzystając z FindComponent usunąć obiektu. Zależy mi na tym, żeby nie tworzyć kolejnych tablic.

Czy TenPanel.FindImage... też nic nie znajduje? I najlepiej nadawać sobie jakąs cyfre w nazwie po tych Image, a później móc się do tego odoływać w pętli. Oczywiście sprawdzając czy FindComponent(Nazwa + IntToStr(IteratorPetli)_`. Tak ja bym kombinował.

0

Zależy mi na tym, żeby nie tworzyć kolejnych tablic.

A to dlaczego? Dzięki wpakowaniu referencji do wszystkich dynamicznie tworzonych komponentów nie miałbyś najmiejszego problemu z ich tworzeniem i zwalnianiem z pamięci, a tak to niepotrzebne kombinacje odchodzą;

Jak nie chcesz mieć jakiejś globalnej macierzy to zrób prostą klasę zarządzającą tymi komponentami, która będzie zawierać listę wszystkich tworzonych TImage, ale ładniej opakowanych; Referencję do instancji takiej klasy przechowuj w np. w polu klasy formularza i określ do niej dostęp albo specjalnie przygotowaną do tego celu właściwością (zwracającą wskaźnik na instancję klasy), albo dodaj odpowiednie metody do klasy formularza; Pole takiej klasy listy twórz w konstruktorze formularza, a zwalniaj w destruktorze - dzięki temu ładnie posprzątasz po sobie;

Zawsze to lepsze, niż zabawa z szukaniem komponentów.

0

Kłopotu z nazwami nie ma załatwia to switch.
Kod

Panel1.TImage(FindComponent('aa1')).Visible:=False; 

zwraca błąd deklaracji (jej braku) dla TImage oraz Missing operator or semicolon.

Imag'ów ma być określona ilość około 5-8 na chwilę obecną jeszcze nie zdecydowałem ile sztuk będzie potrzebne lecz zmieści się we wspomnianej granicy.
Odnośnie operacji na dynamicznie tworzonych elementach mam duże doświadczenie jednak rozłożyło mnie odniesienie się do komponentu stworzonego na panelu (jak we wspomnianym wątku). Niby komponent Image niby ma nazwę a nie da się do niego odnieść a odniesienie się do niego przez jego nazwę zwraca błąd Record, object or class type required.
Moje pytanie brzmi jak się prawidłowo odnieść do obiektu, jeśli został stworzony jak w pierwszym poście i posiada nazwę jak w pierwszym poście, znajduje się na Panelu1.
Załóżmy, że chcę go ukryć i korzystam z ..............visible:=Flase.
Do testów można wrzucić te fragmenty kodu, które podałem i spokojnie powinny wystarczyć:
-tworzymy obiekt dynamicznie (post 1)
-odnosimy się do niego i coś zmieniamy (np widoczność, czy "traktujemy" go destruktorem).

2

TImage(Panel1.FindComponent('aa1')).Visible:=False;
Jeżeli możesz je wszystkie postawić od razu to możesz do nich odwoływać się: TImage(Panel1.Controls[i]).Visible:=False; gdzie i liczone od 0

0

Dzięki bardzo _13th_Dragon to załatwia sprawę i w pełni mnie satysfakcjonuje.

0

Mam podobny problem. Głównym komponentem programu jest PageControl w nim znajdują się zakładki - strony. Działanie programu bazuje na tym że w zdarzaniu OnShow z bazy MySQL pobierany są rekordy na których podstawie tworzone są dynamicznie przyciski - Button. Ich ilość jest różna w zależności od tabeli z której ładujemy dane. Program działa dobrze jednak po nieprzerwanej pracy program zaczyna zużywać bardzo dużo porocesora i pamięci. Chciałem zniszczyć wszystkie powstałem przyciski w zdarzeniu OnHide. Na TabSheet nie znajdują się inne komponenty.

Próbowałem następujących rozwiązań:

TButton(FindComponent('przycisk1')).Destroy;

gdzie w momencie tworzenia nazwałem przyciski kolejno

opcja druga

TButton(TabSheet.PageControl.Pages[2]).Destroy;

Każde z tych rozwiązań generuje błąd.

Zapewne rozwiązań jest wiele. Program pisany jest po linux'em. Proszę o podpowiedź jak mogę to zrobić w prosty sposób.

dodanie znaczników <code class="delphi"> - @furious programming

1

Destruktor wywołuje się metodą Free a nie Destroy

Do not call Destroy directly in an application. Instead, call Free.

a opcja 2 to nie wiem dlaczego chcesz rzutować TTabSheet na TButton. Nadmierne zużycie procesora i pamięci świadczy o tym że masz nieźle "namieszane" w tym programie.

Skoro na TabSheet nie ma innych komponentów poza tymi buttonami to najprościej tak:

while TabSheet.ControlCount > 0 do
    TabSheet.Controls[0].Free;

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