Delphi-PRAXiS

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Object-Pascal / Delphi-Language (https://www.delphipraxis.net/32-object-pascal-delphi-language/)
-   -   Delphi EAbstract Error beim Entfernen aus verketteter Liste (https://www.delphipraxis.net/51686-eabstract-error-beim-entfernen-aus-verketteter-liste.html)

mrmoe 17. Aug 2005 09:11


EAbstract Error beim Entfernen aus verketteter Liste
 
Liste der Anhänge anzeigen (Anzahl: 1)
HI, ich habe ein seltsames Problem (oder ich bin einfach zu blöd dazu :lol: )
ich habe mir eine neue Klasse von Panels erstellt um die auf einem Form untereinander zu haben, dabei sollen beliebig neue Panels hinzugefügt und bei einer Vergrößerung eines Panels alle darunterliegenden iterativ entsprechend verschoben werden, das klappt auch ganz gut. Das Problem ist nur dass wenn ich das 2. oder 3. Panel von oben (also das 2. oder 3. in der Liste) entfernen will dann haut der mir alles um die Ohren. bei den anderen klappt das wunderbar.

Hier die Objekt-Definition:
Delphi-Quellcode:
type myPanel = class(TPanel)
  procedure expand(val: integer; Sender: TObject);
  procedure move(val: integer; Sender: TObject);
  procedure remove_it(Sender: TObject);
 private
  childP: myPanel;
  parentP: myPanel;
 public
  property childPanel: myPanel read childP write childP;
  property parentPanel:myPanel read parentP write parentP;
end;
Ich hab also Vorgänger und Nachfolger jedes Elements, beim Erstellen werden entsprechend die nil´s richtig verteilt wenn es das erste oder letzte Element ist. Bitte nicht über das "Sender: TObject" wundern, damit gebe ich der Methode die Information auf den Weg in welchem Panel gerade ein Button etc. geklickt wurde (ich weiss geht bestimmt auch anders aber so klappts erstmal)

und hier die Methode zum Entfernen:
(in Form1.letztes merke ich mir welches das letzte Element der Panel-Liste ist)
Delphi-Quellcode:
procedure myPanel.remove_it(Sender: TObject);
begin

        if Sender is myPanel then begin
         //einziges Element ?
         if (myPanel(Sender).parentPanel = nil) and (myPanel(Sender).childPanel = nil) then
         begin
          form1.letztes:=nil;
          myPanel(Sender).Destroy;
         end
         //erstes Element ?
         else if myPanel(Sender).parentPanel=nil then
         begin
          myPanel(Sender).childPanel.parentPanel:=nil;
          myPanel(Sender).childPanel.move(myPanel(Sender).Height*(-1)-10,myPanel(Sender).childPanel);
          myPanel(Sender).Destroy;
         end
         //letztes Element ?
         else if myPanel(Sender).childPanel=nil then
         begin
          myPanel(Sender).parentPanel.childPanel:=nil;
          form1.letztes:=myPanel(Sender).parentPanel;
          myPanel(Sender).move(myPanel(Sender).Height*(-1)-10,myPanel(Sender));
          myPanel(Sender).Destroy;
         end
         //mittel Element ?
         else if (myPanel(Sender).childPanel <> nil) and (myPanel(Sender).parentPanel <> nil) then
         begin
          myPanel(Sender).parentPanel.childPanel:=myPanel(Sender).childPanel;
          myPanel(Sender).childPanel.parentPanel:=myPanel(Sender).parentPanel;
          myPanel(Sender).childPanel.move(myPanel(Sender).Height*(-1)-10,myPanel(Sender).childPanel);
          myPanel(Sender).Destroy;
         end;

       end; // if is myPanel
end;
wie gesagt es kommt nur eine AV wenn ich das 2. oder 3. Element löschen will.
->und jetzt wirds verrückt: wenn ich auf dem hauptformular ein label platziere dann kommt der fehler nur noch beim ersten element der liste

was mach ich falsch ? muss ich etwa alles umkrempeln ? seh ich den wald vor lauter bäumen nicht ? wird es morgen regnen ?
-fragen über fragen-

gruß,
der moe
(datei zum testen angehängt)

mrmoe 17. Aug 2005 10:12

Re: Access Violation beim Entfernen aus verketteter Liste
 
ich habs (hoffe ich zumindest ;) ) falsch gedacht s. unten

der fehler lag beim anlegen der objekte(panels), dies geschah über eine onClick-Routine einer comboBox:

Delphi-Quellcode:
procedure TForm2.ComboBox1Click(Sender: TObject);
var lab: TLabel;
    cb: mycb;
    pan: myPanel;
    img: myImg;
begin
 lab:=TLabel.create(Form1);
 cb:=mycb.Create(Form1);
 pan:=myPanel.Create(Form1);
 img:=myImg.Create(Form1);

 pan.Visible:=true; pan.Color:= clSilver;
 pan.Width:=350;
 pan.Height:=40;
 pan.Left:=20;
 pan.BevelInner:=bvRaised;
 pan.BevelOuter:=bvLowered;

 // erstes erzeugen ------------
 if form1.letztes=nil then begin
  pan.parentPanel:=nil;
  pan.childPanel:=nil;
  form1.letztes:=pan;
  pan.Top:=50;
 end
 // weitere erzeugen -----------
 else begin
   pan.parentPanel:=form1.letztes;
   pan.childPanel:=nil;
   form1.letztes.childPanel:=pan;
   pan.Top:=form1.letztes.Top+form1.letztes.height+10;
   form1.letztes:=pan;
 end;

/// schnipp - etc. ...
end;
es muss aber lauten:

lab:=TLabel.create(self);
cb:=mycb.Create(self);
pan:=myPanel.Create(self);
img:=myImg.Create(self);

ich dachte das in Klammern hinter Create steht für das Parent-Objekt, und da die Panels auf Form1 kommen sollen hatte ich eben Form1 statt self drinstehn. ich sag nur: :wall:

naja jetzt gehts wie gesagt, viell. hilfts ja mal jemanden weiter


///////////////////////-----------------/////////////////////
mist Doch zu früh gefreut, jetzt bekomme ich immer nachdem ich mehr als 10 elemente aus der liste lösche bei einigen einen EAbstract Error der vorher nicht kam.
Ich hab schonmal danach gegoogelt und alles was ich finden konnte war dass der auftritt wenn man abstrakte methoden verwendet. bloss bitt wo mach ich das (der abstrakte fehler kommt immer beim self.destroy des panels)

hier nochmal der angepasste Quelltext
Delphi-Quellcode:
procedure myPanel.remove_it();
begin
         //einziges Element ?
         if (self.parentPanel = nil) and (self.childPanel = nil) then
         begin
          form1.letztes:=nil;
          self.move(self.Height*(-1)-10);
         end
         //erstes Element ?
         else if self.parentPanel=nil then
         begin
          self.childPanel.parentPanel:=nil;
          self.childPanel.move(self.Height*(-1)-10);
         end
         //letztes Element ?
         else if self.childPanel=nil then
         begin
          self.parentPanel.childPanel:=nil;
          form1.letztes:=self.parentPanel;
          self.move(self.Height*(-1)-10);
         end
         //mittel Element ?
         else if (self.childPanel <> nil) and (self.parentPanel <> nil) then
         begin
          self.parentPanel.childPanel:=self.childPanel;
          self.childPanel.parentPanel:=self.parentPanel;
          self.childPanel.move(self.Height*(-1)-10);
         end;

       self.comboBox.Items.Add(self.filterName);
       if self.comboBox.Items.count=1 then self.combobox.visible:=true;
       self.destroy;    <------ hier kommt der fehler (aber nicht bei allen)
end;
Ich hab auch mal in den definitionen der geerbten TPanel-Klasse nachgeschaut und auch in der TCustomControl noch eine Ebene höher, aber nirgends eine abstrakte Methode zu finden die ich erst überschreiben müsste...

kann irgendwer helfen ????

mrmoe 17. Aug 2005 15:10

Re: EAbstract Error beim Entfernen aus verketteter Liste
 
ist ja schlimm, muss man seinen eigen thread beantworten :tongue:

na egal, ich weiss jetzt woran es lag:

immer wenn ich ein panel-element löschen wollte hab ich dazu einen lösch-image-button geklickt der selber teil des panels oder vielmehr des von mir erzeugten abgeleiteten panel-objektes war.
Die ungewöhnlichen Effekte (wenn ein Label oder ein memo auf dem Hauptformular ist dann ändert sich das fehler-verhalten etc.) hängen damit wohl zusammen - und zwar ruft dann die onClick Prozedur des Lösch-Buttons die lösch-methode (myPanel.remove_it) auf und teilweise wurde dann wohl dem lösch button der boden unter den füssen weggezogen bevor die lösch-routine fertig war soll heissen seine speicheradressen zeigen ins leere.

ich habs nun so gemacht dass der lösch-button einen timer auslöst (von 10 millisek.) und sich in einer extra variable gemerkt wird welches panel-element gelöscht werden soll so dass alle routinen von auf dem panel befindlichen elementen erst abgearbeitet werden können bevor es den speicher freigibt (und damit auch den speicher der child-elemente auf dem panel)
ich weiss ist zwar nicht die sauberste variante und wohl auch nicht 100% koscher aber der löschbutton muss teil des panels bleiben anders gehts nicht.


die letzte frage die nun bleibt ist wieso es überhaupt mehrmals so ging bevor der fehler kam und warum dann ein EAbstract Error ausgeworfen wird anstatt einer Speicherzugriffsverletzung

shmia 17. Aug 2005 15:31

Re: EAbstract Error beim Entfernen aus verketteter Liste
 
Zitat:

Zitat von mrmoe
Die ungewöhnlichen Effekte (wenn ein Label oder ein memo auf dem Hauptformular ist dann ändert sich das fehler-verhalten etc.) hängen damit wohl zusammen - und zwar ruft dann die onClick Prozedur des Lösch-Buttons die lösch-methode (myPanel.remove_it) auf und teilweise wurde dann wohl dem lösch button der boden unter den füssen weggezogen bevor die lösch-routine fertig war soll heissen seine speicheradressen zeigen ins leere.

Das hast du richtig erkannt. :mrgreen:
In der Code-Library wird erklärt, wie man das ohne Timer umgehen kann:
http://www.delphipraxis.net/internal...ct.php?t=29732

mrmoe 17. Aug 2005 16:37

Re: EAbstract Error beim Entfernen aus verketteter Liste
 
danke für den Link :thumb:

ist natürlich wesentlich eleganter und stabiler so (denn ich denk mal dass unter umständen die lösung mit dem timer auch fehler bringt wenn der rechner grad anderweitig ausgelastet ist oder sowas)


Alle Zeitangaben in WEZ +1. Es ist jetzt 02:32 Uhr.

Powered by vBulletin® Copyright ©2000 - 2025, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024-2025 by Thomas Breitkreuz