Zagnieżdżanie dynamicznie tworzonych paneli

0

Po wciśnięciu przycisku tworzony jest PanelW, na którym jest umieszczony label i przycisk, taki sam jak ten który utworzył PanelW. Po wciśnięciu przycisku na PanelW powinien zostać stworzony dynamicznie PanelW jeszcze raz, a label który powienien mieć taką samą nazwę powinien wyświetlić inny tekst. Problem jednak, że on już istnieje i tekst na labelu jest ciągle taki sam.

W zdarzenie onClick chciałbym umieścić sprawdzanie czy PanelW już istnieje a jeśli tak to go zwolnić, żeby móc postawić od nowa. Próbowałem jak poniżej, ale nie daje to żadnego efektu, Label.Captio jest bez zmian.

if FindComponent('PanelW') <> nil then
  //showmessage('istnieje');
  PanelW.Free; 
 

Po umieszczeniu ShowMessage zaobserwowałem, że warunek nie jest spełniony nigdy.

2

Czy na pewno ustawiasz nazwę panelu na PanelW, czy tak tylko sobie zmienną nazwałeś?

1

To moze trzymaj to w jakims TObjectList? :)

1

Po pierwsze. Jeśli nie zrobiłeś:

 
panel.Name := 'PanelW';

to niczego Ci nie znajdzie.
Po drugie samo:

panel.Free
nic Ci nie da. Owszem, zwolni pamięć, ale nie wyniluje Ci tej referencji. Jeśli obiekt musisz mieć znilowany, to używasz FreeAndNil(obj).

Po trzecie. Widzę, że masz zmienną panelW. Więc po co szukasz tej kontrolki w ten sposób? Najpewniej tworzysz ją:

 
panelW:=TPanel.Create

Czyli referencję do tego masz w panelW (chyba, że jest to zmienna lokalna, ale nie wynika to z kodu, który podałeś). Więc zamiast:

 
FindComponent('PanelW')

wystarczy, że zrobisz:

 
if panelW <> nil
  FreeAndNil(panelW);
0
dani17 napisał(a)

Po wciśnięciu przycisku na PanelW powinien zostać stworzony dynamicznie PanelW jeszcze raz, a label który powienien mieć taką samą nazwę powinien wyświetlić inny tekst.

Się nie da szefie - nazwa komponentu musi być unikalna w skali całego formularza.

0

Okej, widzę gdzie mam błąd. Ale tak na prawdę to nie rozwiązuje mojego problemu. Bo nadal nie działa to tak jak bym chciał, a nawet więcej, niby nie ma problemu nigdzie, cały kod się wykonuje ale i tak wyskakuje

Project raised exception class 'EXTERNAL: SIGSEGV'

At address: 2E005D8

Kod programu w uproszczeniu:

procedure TProgram.FormCreate(Sender: TObject);
begin
  PanelW := TPanel.Create(Program);
  with PanelW do
  begin
    Parent := Program;
    Width := Parent.Width;
    Height := ParentHeight;
    Color := KolorGlowny;
    Left := 0;
    Top := 0;
  end;

  LNazwa := TLabel.Create(PanelW);
  with LNazwa do
  begin
    Parent := PanelW;
    Left := 5;
    Top := 5;
    Caption := 'Jakaś nazwa';
    onClick := LabelKlik;
  end;
end;

procedure TProgram.LabelKlik(Sender: TObject);
var
  I: Integer;
  FPanel: TPanel;
begin
  Sender := FPanel;

  if PanelW <> nil then
    begin
      for I := PanelW.ControlCount - 1 downto 0 do
        PanelW.Controls[I].Free;
    end;

  PanelW := TPanel.Create(Program);
  with PanelW do
  begin
    Parent := Program;
    Width := Parent.Width;
    Height := ParentHeight;
    Color := KolorGlowny;
    Left := 0;
    Top := 0;
  end;

  LNazwa := TLabel.Create(PanelW);
  with LNazwa do
  begin
    Parent := PanelW;
    Left := 5;
    Top := 5;
    Caption := 'Jakaś nazwa';
    onClick := LabelKlik;
  end;
end;
 
0

Prawdopodobnie w drugim with chciałeś jednak napisać LNazwa, a nie PanelW.

0

To prawda, już poprawione. Natomiast w kodzie jest prawidłowo. Błąd jedynie był przy pisaniu na forum. Mimo wszystko dalej wychodzi ten sam wyjątek.

0

@dani17 - destruktor PanelW sam zwolni komponenty w nim zagnieżdżone, więc mu w tym nie przeszkadzaj;

Poza tym jak nie wiesz gdzie wywoływany jest wyjątek to uruchom program przez IDE i (po zaistnieniu wyjątku) w okienku błędu kliknij guzik break - wtedy zostanie pokazana w edytorze linijka, która wyrzuciła wyjątek;

A tak w ogóle to nie możesz w taki sposób zwolnić komponentu, którego zdarzenie jest aktualnie wykonywane; Już ten problem był na forum poruszany;

onClick := LabelKlik;

Używasz dyrektywy {$MODE DELPHI}? Małpka powinna być przed nazwą metody.

0

Dlatego chciałem wykorzystać Sender := A. Chociaż to był pomysł z głowy i nie wiem czy to ma jakikolwiek sens.Jeśli nie to tak jak już było pisane, trzeba będzie użyć Timera. Dyrektywę delphi mam.

0

Dlatego chciałem wykorzystać Sender := A. Chociaż to był pomysł z głowy i nie wiem czy to ma jakikolwiek sens.Jeśli nie to tak jak już było pisane, trzeba będzie użyć Timera.

Ale wiesz, że Sender posiada referencję kontrolki, której zdarzenie jest wykonywane? Jeśli przypiszesz metodę LabelKlik (co to za nazwa?) do etykiety LNazwa to w Sender będzie wskazanie na LNazwa; Nie tędy droga;

Ten problem był już poruszany niedawno (to był chyba Twój wątek), w którym @abrakadaber podał bodajże dwa rozwiązania tego problemu, poprzez wysłanie własnego komunikatu do okna i przez timer; Znajdź ten wątek i sprawdź co zostało podane;

Dyrektywę delphi mam.

Po co? Kod piszesz dla FPC, więc używaj dyrektywy {$MODE OBJFPC}; Do tej pory nie wspominałeś o kompatybilności z Delphi na poziomie kodu, więc nie jest Ci to do niczego potrzebne i będzie tylko przeszkadzać.

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