[Delphi] Błąd "Access violation" - problem

0

Witam,
męczę się już 2 dzień z błędem, którego nijak nie mogę pojąć, rozwiązać ani cokolwiek z nim zrobić. Otóż piszę program, a w nim mam takie procedury:

procedure TForm1.ListaClick (Sender: TObject) ;
var
 i :integer ;
begin
try
 for i:= 0 to Length(ListaStopni[NrWybranejOsoby].Zadania)-1 do
  begin
  TEdit(self.FindComponent('SzczegolyZadaniaZaliczone' + IntToStr(i+1))).Free ;
  TShape(self.FindComponent('SzczegolyZadaniaPoleZaliczone' + IntToStr(i+1))).Free ;
  TMaskEdit(self.FindComponent('SzczegolyZadaniaData' + IntToStr(i+1))).Free ;
  TShape(self.FindComponent('SzczegolyZadaniaPoleData' + IntToStr(i+1))).Free ;
  TMemo(self.FindComponent('SzczegolyZadaniaTresc' + IntToStr(i+1))).Free ;
  TLabel(self.FindComponent('SzczegolyZadaniaLP' + IntToStr(i+1))).Free ;
  TShape(self.FindComponent('SzczegolyZadaniaPoleLP' + IntToStr(i+1))).Free ;
  TSpeedButton(self.FindComponent('SzczegolyZadaniaDodaj' + IntToStr(i+1))).Free ;
  TSpeedButton(self.FindComponent('SzczegolyZadaniaUsun' + IntToStr(i+1))).Free ;
  end ;
finally end ;

NrWybranejOsoby:= StrToInt(Copy(TLabel(Sender).Name, 6, Length(TLabel(Sender).Name)-5)) ; 

for i:= 0 to Length(ListaStopni[NrWybranejOsoby].Zadania)-1 do
 begin
 with TShape.Create(self) do
  begin
  Name:= 'SzczegolyZadaniaPoleLP' + IntToStr(i+1) ;
  Top:= -1 + i*59 ;
  Left:= -1 ;
  Width:= 27 ;
  Height:= 60 ;
  Brush.Color:= clBtnFace ;
  Parent:= ScrollBox3 ;
  Visible:= True ;
  end ;
 if i > 0 then
  with TSpeedButton.Create(self) do
   begin
   Name:= 'SzczegolyZadaniaUsun' + IntToStr(i+1) ;
   Top:= i*59 + 28 ;
   Left:= 0 ;
   Width:= 25 ;
   Height:= 15 ;
   Caption:= '-' ;
   Visible:= True ;
   Parent:= ScrollBox3 ;
   Hint:= 'Usuń zadanie' ;
   ShowHint:= True ;
   with Font do
    begin
    Name:= 'Verdana' ;
    Size:= 10 ;
    Style:= [fsBold] ;
    end ;
   //OnClick:= ZadaniaUsunClick ;
   end ;
 with TSpeedButton.Create(self) do
  begin
  Name:= 'SzczegolyZadaniaDodaj' + IntToStr(i+1) ;
  Top:= i*59 + 43 ;
  Left:= 0 ;
  Width:= 25 ;
  Height:= 15 ;
  Caption:= '+' ;
  Visible:= True ;
  Parent:= ScrollBox3 ;
  Hint:= 'Dodaj nowe zadanie' ;
  ShowHint:= True ;
  with Font do
   begin
   Name:= 'Verdana' ;
   Size:= 10 ;
   Style:= [fsBold] ;
   end ;
  OnClick:= ZadaniaDodajClick ;
  end ;
 with TLabel.Create(self) do
  begin
  Name:= 'SzczegolyZadaniaLP' + IntToStr(i+1) ;
  Top:= 1 + i*59 ;
  Left:= 5 ;
  Parent:= ScrollBox3 ;
  Visible:= True ;
  Caption:= IntToStr(i+1) ;
  Font.Size:= 10 ;
  Font.Name:= 'Verdana' ;
  ShowHint:= True ;
  Hint:= 'Liczba porządkowa zadania' ;
  end ;
 with TMemo.Create(self) do
  begin
  Name:= 'SzczegolyZadaniaTresc' + IntToStr(i+1) ;
  Top:= -1 + i*59 ;
  Left:= 25 ;
  Parent:= ScrollBox3 ;
  Visible:= True ;
  Text:= ListaStopni[NrWybranejOsoby].Zadania[i].Tresc ;
  Font.Size:= 10 ;
  Font.Name:= 'Verdana' ;
  Width:= 400 ;
  Height:= 60 ;
  ScrollBars:= ssVertical ;
  WantReturns:= False ;
  Ctl3D:= False ;
  OnExit:= ZadaniaExit ;
  Color:= clBtnFace ;
  OnEnter:= ZadaniaEnter ;
  OnKeyPress:= ZadaniaKeyPress ;
  end ;
 with TShape.Create(self) do
  begin
  Name:= 'SzczegolyZadaniaPoleData' + IntToStr(i+1) ;
  Top:= -1 + i*59 ;
  Left:= 425 ;
  Width:= 60 ;
  Height:= 60 ;
  Brush.Color:= clBtnFace ;
  Parent:= ScrollBox3 ;
  Visible:= True ;
  end ;
 with TMaskEdit.Create(self) do
  begin
  Name:= 'SzczegolyZadaniaData' + IntToStr(i+1) ;
  Top:= 22 + i*59 ;
  Left:= 431 ;
  Width:= 49 ;
  Color:= clBtnFace ;
  Parent:= ScrollBox3 ;
  Visible:= True ;
  BorderStyle:= bsNone ;
  EditMask:= '99\-9999;1;_' ;
  MaxLength:= 7 ;
  Text:= ListaStopni[NrWybranejOsoby].Zadania[i].Data ;
  Font.Name:= 'Verdana' ;
  ShowHint:= True ;
  Hint:= 'Przewidywany termin ukończenia zadania w formacie MM-RRRR' ;
  Height:= 16 ;
  OnExit:= ZadaniaExit ;
  OnEnter:= ZadaniaEnter ;
  OnKeyPress:= ZadaniaKeyPress ;
  end ;
 with TShape.Create(self) do
  begin
  Name:= 'SzczegolyZadaniaPoleZaliczone' + IntToStr(i+1) ;
  Top:= -1 + i*59 ;
  Left:= 484 ;
  Width:= 125 ;
  Height:= 60 ;
  Brush.Color:= clBtnFace ;
  Parent:= ScrollBox3 ;
  Visible:= True ;
  end ;
 with TEdit.Create(self) do
  begin
  Name:= 'SzczegolyZadaniaZaliczone' + IntToStr(i+1) ;
  Top:= 21 + i*59 ;
  Left:= 487 ;
  Width:= 119 ;
  Color:= clBtnFace ;
  Parent:= ScrollBox3 ;
  Visible:= True ;
  BorderStyle:= bsNone ;
  Text:= ListaStopni[NrWybranejOsoby].Zadania[i].Zaliczone ;
  Font.Name:= 'Verdana' ;
  ShowHint:= True ;
  Hint:= 'Potwierdzenie wykonania zadania (osoba potwierdzająca)' ;
  Height:= 16 ;
  OnExit:= ZadaniaExit ;
  OnEnter:= ZadaniaEnter ;
  OnKeyPress:= ZadaniaKeyPress ;
  end ;
 end ;

end ;
procedure TForm1.ZadaniaDodajClick (Sender: TObject) ;
begin
ListaClick (TLabel(self.FindComponent('Lista0'))) ;
end ;

Tablica rekordów, do której się odwołuję wiele razy, wygląda tak (jest uzupełniona z pliku w innej procedurze:

type
 TListaZadan = record
  Tresc, Data, Zaliczone :string ;    
  end ;
 TStopien = record
  Zdobywajacy, Opiekun, Nazwa, DataOtwarcia, DataZamkniecia, Zamkniety :string ;
  Zadania :array of TListaZadan ;
  end ;

var
  Form1: TForm1;
  ListaStopni :array of TStopien ;
  NrWybranejOsoby :integer ;

Tworzy się tam przycisk (SzczegolyZadaniaDodaj), który na chwilę obecną po kliknięciu jakby odświeża to, usuwa te komponenty i tworzy je jeszcze raz. Problem w tym, że po parokrotnym kliknięciu go (różnie, czasami od razu, czasami za 3-4 razem) wyskakuje błąd "Access violation at address ... in module 'Project1.exe'. Read of address .....".

Błąd ten wyskakuje tylko wtedy, gdy klikam przycisk. Gdy nawet wielokrotnie nacisnę komponent Label, który ma OnClick:= ListaClick ; nic się nie dzieje... I to mnie najbardziej dziwi w tym wszystkim.

Program jest niemal na ukończeniu, miał być gotowy do końca weekendu, ale przez ten błąd zatrzymałem się w miejscu. Bardzo proszę o pomoc - jak to naprawić?

0

a to Lista0 gdzie masz???

BTW strasznie to jestr napisane

0
procedure TForm1.TworzListe ;
var
 i :integer ;
begin
for i:= 0 to Length(ListaStopni)-1 do
 with TLabel.Create(self) do
  begin
  Name:= 'Lista' + IntToStr(i) ;
  Top:= 10 + i * (Height+5) ;
  Left:= 10 ;
  Parent:= ScrollBox1 ;
  Visible:= True;
  Font.Name:= 'Verdana' ;
  Font.Size:= 8 ;
  Caption:= ListaStopni[i].Zdobywajacy ;
  OnMouseEnter:= ListaMouseEnter ;
  OnMouseLeave:= ListaMouseLeave ;
  OnClick:= ListaClick ;
  end ;
end ;

podczas prób, gdy wyskakiwały błędy, nie robiłem żadnych cudów z nazwą itd. tylko podałem właśnie "Lista0" żeby najpierw rozwiązać problem, a potem, gdy już będzie działać, zrobić żeby działało też dla "Lista1" itd, to nie problem.

no tworzę dużo dynamicznych komponentów... jeśli jest jakiś sposób, by to estetyczniej rozwiązać, chętnie się nauczę ;)

0

Jeśli Lista0 nie istnieje to w ListaClick parametr Sender = nil, więc nic dziwnego że poniższa linia wyrzuca wyjątek.

NrWybranejOsoby:= StrToInt(Copy(TLabel(Sender).Name, 6, Length(TLabel(Sender).Name)-5)) ; 

Następnym razem napisz, na której linii program się wykrzacza, będzie łatwiej.

0

ale ja mu podaję

ListaClick (TLabel(self.FindComponent('Lista0'))) ;

a ten komponent istnieje. Poza tym jak usuwałem podaną przez Ciebie linię już wcześniej i podawałem np. NrWybranejOsoby:= 0; to niczego nie zmieniało.
Obawiam się, że to coś z nadpisaniem pamięci czy czymś takim. Jak usunąłem większość tych dynamicznych komponentów zostawiając tylko SzczegolyZadaniaPoleLP i SzczegolyZadaniaDodaj to błąd wyskakiwał dopiero po kilkunastu naciśnięciach buttona. Przy czym niezależnie, ile razy nacisnę Label "Lista0", błąd nie wyskakuje, mimo że przypisana do OnClick procedura jest taka sama.

0

W której linii jest błąd?

0

komunikat wyskakuje, ale program działa dalej. nie pokazuje linijki błędu :/

0

Włącz wyświetlanie błędów debuggera (Tools -> Options -> Language exceptions) i po wyrzuceniu wyjątku wciśnij Break. Debugger ustawi się na linii z błędem.

0

przeszukałem pół internetu, by się czegoś dowiedzieć, co mogłoby pomóc. jestem mądrzejszy o to, że access violation wyskakuje przy odwołaniach do nieistniejących komponentów. ale w moim programie nie dzieje się to od razu, tylko po wielu kliknięciach...

nie rozumiem GDZIE może być ten błąd. zmieniłem na NrWybranejOsoby:= 0; i nigdzie w procedurze nie wykorzystywany jest sender.

czytałem tu: http://regedit.gamedev.pl/produkcje/artykuly/liczba32bitowa.php5 w rozdziale "Bezpieczeństwo wartości pustych" o Access Violation. napisali że "tego typu błędy są wyjątkowo wredne i trudne do zlokalizowania". Zgadzam się...

ale napisali też takie coś:

Jeśli zwalniasz pamięć, wszystkim wskaźnikom, które na ten obszar wskazywały przypisz wartość nil. W przeciwnym wypadku będą one skierowane na przypadkowy blok pamięci.

Jak to zrobić? bo ja usuwam dynamiczne komponenty robiąc TEdit(self.FindComponent(...)).Free może dodanie tego "nil" pomoże...

0

w Language exceptions mam zaznaczone wszystko, ale po wyskoczeniu komunikatu jak naciskam Break nic się nie dzieje?

0
FreeAndNil(myObject);
0

całe zdarzenie ma miejsce tylko wtedy, gdy akcją komponentu z procedury jest wykonanie tej procedury, czyli np.

procedure Klik (Sender: TObject) ;
begin
with TButton.Create(self) do
  begin=
  Top:=1;
  Left:= 1 ;
  Width:= 200 ;
  Height:= 60 ;
  Parent:= self ;
  Visible:= True ;
  Caption:= 'kliknij';
  OnClick:= Klik ;
  end ;
end ;

gdy wywołuję tą procedurę klikając na komponent statyczny bądź dynamiczny utworzony poza nią nie ma problemu.

chwilowo, ponieważ się śpieszę z programem, obszedłem to właśnie w ten sposób - mam tylko jeden przycisk, umieszczony statycznie. nie spełnia to moich początkowych założeń co do programu, ale przynajmniej działa.

jeśli ktoś wiedziałby, co z tym zrobić, byłbym bardzo wdzięczny za pomoc.

0

Ponieważ w jednej procedurze tworzysz dynamicznie wiele komponentów proponuję żebyś stworzył sobie Framea z tymi wszystkimi komponentami i przypisanymi do nich zdarzeniami i w programie tworzył dynamicznie tylko tego Framea.

0

dzięki. całkiem niezłe rozwiązanie. ale chyba nie do końca kumam...

robię File -> New -> Frame
umieszczam na tym Frame komponenty
i jak teraz dynamicznie wyświetlić go wiele razy na Formie?

0

Dokładnie tak samo jak tworzysz nowy komponent

with TMyFrame.Create(Self) do begin
  Parent := Self;
  ...
end;

Oczywiście musisz dodać unit z klasą TMyFrame do sekcji uses.

Jeśli chcesz aby był wyświetlony wiele razy radzę stworzyć tablicę lub listę tych Framów. Łatwiej będzie na nich operować niż za pomocą FindComponent.

Wszystkie zdarzenia i operacje wykonywane w obrębie samego Framea (nie dotyczące reszty aplikacji) postaraj się przenieść do kodu Framea.

0

dzięki, wszystko działa :)

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