Zamykanie ListBox

  • Rejestracja: dni
  • Ostatnio: dni
0

Witam.
Znalazłem na forum temat, dzięki któremu zrobiłem sobie otwieranie ListBox'a po kliknięciu:

Kopiuj


const
  SynMemo_Name = 'SynMemo';
  ListBox_Name = 'List';
var
  LB : TListBox;
  Idx : integer;
  SynMemo : TSynMemo;
begin
  if Key = '<a' then
  begin
 Idx := PageControl1.ActivePageIndex + 1;
    LB := TListBox(Self.FindComponent(ListBox_Name + IntToStr(Idx)));
    if LB = nil then
    begin
      SynMemo := TSynMemo(Self.FindComponent(SynMemo_Name + IntToStr(Idx)));
      LB := TListBox.Create(Self);
      LB.Name := ListBox_Name + IntToStr(Idx);
      LB.Parent := SynMemo;
      LB.Items.Add(SynMemo.Name);
    end;
  end;

Ale jak zamknąć ten ListBox przy pomocy:

Kopiuj
If Key = '>' Then

jestem zielony, więc proszę o wyjaśnienie czego użyć.

pelsta
  • Rejestracja: dni
  • Ostatnio: dni
  • Postów: 819
0
Kopiuj
LB.Free
  • Rejestracja: dni
  • Ostatnio: dni
0

tak, ale wywala wtedy błąd przy naciśnięciu klawisza,
Chodzi mi o to, że: Jeśli LB jest otwarty to LB.Free, else nie podejmuj akcji

pelsta
  • Rejestracja: dni
  • Ostatnio: dni
  • Postów: 819
0

Może zdradzisz jaki błąd.

  • Rejestracja: dni
  • Ostatnio: dni
0

Access violation at address 00494757 in module 'Project2.exe' Read of address...

flowCRANE
  • Rejestracja: dni
  • Ostatnio: dni
  • Lokalizacja: Tuchów
  • Postów: 12270
0
LabambA napisał(a)

Znalazłem na forum temat, dzięki któremu zrobiłem sobie otwieranie ListBox'a po kliknięciu:

Pierwsze słyszę, żeby ListBox'a można było otworzyć...


Kopiuj
if Key = '<a' then

Jakiego typu jest Key (tak z ciekawości pytam)?


LabambA napisał(a)

Chodzi mi o to, że:
Jeśli LB jest otwarty to LB.Free, else nie podejmuj akcji

Nie otwarty, tylko utworzony; Można to sprawdzić funkcją Assigned(), np. tak:

Kopiuj
if Assigned(LB) then
  //kod jeśli obiekt jest utworzony
else
  //kod jeśli obiekt nie jest utworzony

Jednak i tak wykonujesz sprawdzenie czy funkcja FindComponent coś znalazła, więc tam możesz dopisać else;

LabambA napisał(a)

Ale jak zamknąć ten ListBox przy pomocy:

Kopiuj
If Key = '>' Then

Zwolnić po nim pamięć należy motodą, którą podał Ci @pelsta:

Kopiuj
LB.Free();

Oj kolego, coś mi się widzi, że przydałaby Ci się powtórka z warunków i dynamicznego tworzenia kontrolek, bo pytasz o rzeczy bardzo proste;

LabambA napisał(a)

Access violation at address 00494757 in module 'Project2.exe' Read of address...

Dużo komukolwiek to mówi...

flowCRANE
  • Rejestracja: dni
  • Ostatnio: dni
  • Lokalizacja: Tuchów
  • Postów: 12270
0
Patryk27 napisał(a)

Tak właściwie, Assigned sprawdza czy coś nie jest po prostu nil-em, a nie czy jest utworzone. Obiekt może być nieutworzony, ale wskazywać na jakieś randomowe miejsce w pamięci :P

Słuszna uwaga, jednak:

Kopiuj
((LB <> nil) = (Assigned(LB))) = ((LB = nil) = (not Assigned(LB)))

Czyli nie pomyliłem się :]

  • Rejestracja: dni
  • Ostatnio: dni
0
Patryk27 napisał(a)

Tak właściwie, Assigned sprawdza czy coś nie jest po prostu nil-em, a nie czy jest utworzone.

Jeżeli coś jest nilem to na pewno nie jest utworzone, każde inne miejsce w pamięci teoretycznie może być poprawne. Sprawdzanie z VirtualQuery trwało by zdecydowanie za dużo, a właściwie jest niepotrzebne gdyż każdy poprawny program przyjmuje nil jako wartość specjalną (tzn. nie istniejącą) a każda inna jest postrzegana jako poprawna...

Obiekt może być nieutworzony, ale wskazywać na jakieś randomowe miejsce w pamięci :P

No jeżeli się chce wywalić program to można to zrobić... Ale nie kradnij mi metod na wywalanie programu gdy jest debuggowany ;) .
Dużo częstsza jest sytuacja kiedy obiekt był utworzony w tamtym miejscu ale potem ktoś go zwolnił a wskaźnika nie wyzerował.

Furious Programming napisał(a)

if Assigned(LB) then
//kod jeśli obiekt jest utworzony
else
//kod jeśli obiekt nie jest utworzony

To stwierdzenie jest jak najbardziej poprawne, gdyż wszystko założy że obiekt jest utworzony o ile nie wskazuje na nil.
Coś mi się wydaje że @Patryk27 szuka dziury w całym ;) . Nie widzę żadnej nieścisłości w tym co napisał Furious. Na pewno jest lepiej napisać if assigned(LB) niż if LB<>nil. Natomiast nic nie zagwarantuje ci że obiekt rzeczywiście jest tam gdzie wskazuje wskaźnik, możesz równie dobrze czytać śmieci.

flowCRANE
  • Rejestracja: dni
  • Ostatnio: dni
  • Lokalizacja: Tuchów
  • Postów: 12270
0
-123oho napisał(a)

Natomiast nic nie zagwarantuje ci że obiekt rzeczywiście jest tam gdzie wskazuje wskaźnik, możesz równie dobrze czytać śmieci.

Można jedynie wyłapać wyjątek odpowiednim blokiem jeśli próba odczytania nie powiedzie się, gdy faktycznie zmienna obiektowa obiekt nie jest utworzony, ale nie wskazuje na nil;

Jednak uważam, że obydwa sposoby są równie błędne/bezbłedne - ja jeśli nie korzystam typowo z pointerów zawsze sprawdzam takie rzeczy funkcją Assigned() i nie powiem nic złego, bo nigdy mnie nie zawiodła;

-123oho napisał(a)

Dużo częstsza jest sytuacja kiedy obiekt był utworzony w tamtym miejscu ale potem ktoś go zwolnił a wskaźnika nie wyzerował.

Wtedy warto skorzystać z FreeAndNil();

pelsta
  • Rejestracja: dni
  • Ostatnio: dni
  • Postów: 819
0
LabambA napisał(a):

tak, ale wywala wtedy błąd przy naciśnięciu klawisza,
Chodzi mi o to, że: Jeśli LB jest otwarty to LB.Free, else nie podejmuj akcji

LabambA napisał(a):

Access violation at address 00494757 in module 'Project2.exe' Read of address...

Free automatically calls the destructor if the object reference is not nil. /.../ Unlike Destroy, Free is successful even if the object is nil; so if the object was never initialized, Free won’t result in an error.

Jeżeli lb zadeklarowałeś jako zmienną globalną to kompilator automatycznie przyporządkuje lb:=nil i metoda lb.free nie wywali błędu nawet, gdy lb nie zostało utworzone.
Jeżeli lb zadeklarowałeś jako zmienną lokalną (w procedurze) to początkowo lb wskazuje przypadkowe miejsce w pamięci (wtedy Assigned(lb)=True a także (lb=nil)=False) i jeżeli lb nie zostało utworzone (Create) to metoda lb.free oczywiście wywali błąd.
Podobnie zachowa się procedura FreeAndNil.

flowCRANE
  • Rejestracja: dni
  • Ostatnio: dni
  • Lokalizacja: Tuchów
  • Postów: 12270
0
pelsta napisał(a)

Jeżeli lb zadeklarowałeś jako zmienną globalną to kompilator automatycznie przyporządkuje lb:=nil i metoda lb.free nie wywali błędu nawet, gdy lb nie zostało utworzone.

Jeżeli faktycznie tak zrobił to raczej nie powinno być z tym większego problemu; Jednak lepszym wyjściem jest utworzenie prywatnego (jeśli żaden inny moduł ma z niego nie korzystać) lub publicznego (jeśli ma) pola klasy formularza i operowania na nim, niż pakowanie takich rzeczy do globalnego vara;

pelsta napisał(a)

Jeżeli lb zadeklarowałeś jako zmienną lokalną (w procedurze) to początkowo lb wskazuje przypadkowe miejsce w pamięci (wtedy Assigned(lb)=True a także (lb=nil)=False) i jeżeli lb nie zostało utworzone (Create) to metoda lb.free oczywiście wywali błąd.

Jeśli zmienna jest lokalna to po jej utworzeniu, wykonaniu kodu tego zdarzenia/procedury/funkcji straci do niego referencję i po ponownym wywołaniu nie będzie możliwości wprowadzenia jakichkolwiek modyfikacji, bo zmienna ta nie będzie wskazywać na wczesniej utworzony obiekt; Trzeba by odnaleźć tą kontrolkę przez np. FindComponent() czy FindControl() i zapisać referencję do niej (do zmiennej), ale to w tym przypadku jest bez sensu;


Gdybym musiał zrobić takie coś to na pewno utworzyłbym sobie pole w klasie okna do którego mógłbym się odwoływać kiedy chcę i w jakimkolwiek zdarzeniu/procedurze/funkcji nie tracąc referencji do obiektu i nie musząc kombinować by ją odzyskać; Wtedy wystarczy jedynie sprawdzać co wskazuje i odpowiednio reagować;

Jeśli chce się mieć pewność, że obiekt wskazuje na nil lub na adres gdzie faktycznie znajduje się utworzony obiekt to w zdarzeniu OnCreate formularza można od razu przypisać doń nil, a przy zwalnianiu pamięci obiektu stosować FreeAndNil() i nie sądzę, żeby taka konstrukcja była zawodna;

Często podczas dynamicznego tworzenia kontrolek stosuję takie rozwiązanie i nigdy mnie nie zawiodło;

Zarejestruj się i dołącz do największej społeczności programistów w Polsce.

Otrzymaj wsparcie, dziel się wiedzą i rozwijaj swoje umiejętności z najlepszymi.