Delphi-PRAXiS

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Datenbanken (https://www.delphipraxis.net/15-datenbanken/)
-   -   Delphi Stack Überlauf fehler (https://www.delphipraxis.net/177849-stack-ueberlauf-fehler.html)

Drumbo 1. Dez 2013 10:56

Datenbank: SQL Server 2012 • Version: 11 • Zugriff über: XE 3

Stack Überlauf fehler
 
Guten Morgen,

ich habe vor, dass in meinem DBGrid sobald sich irgendwas in diesem Tut, eine Prozedure aufgerufen wird.
Diese Procedure greift auf die mit dem DBGrid verknüpfte Datenbank zu und durchläuft diese.
Es soll geguckt werden, ob in dem speziellen Datensatz der Artikel bestellt ist oder nicht. In der Datenbank wird existiert dafür ein Boolisches Feld. Die Prozedur sieht wir folgt aus:
Delphi-Quellcode:
procedure TAuftrag_form.BestellbtnCreate();
var
i:integer;
begin

   i:=1;
   Ersatzteil_Dataset.First;
while not Ersatzteil_Dataset.Eof do
  begin

    if Ersatzteil_DatasetBestellt.Value=True then
    begin
      DBAdvGrid4.RemoveButton(7,DBAdvGrid4.Row);
    end;
     Ersatzteil_Dataset.Next;
  end;

 Ersatzteil_Dataset.first;

while not Ersatzteil_Dataset.Eof do
  begin

  if Ersatzteil_DatasetBestellt.Value=False then
    begin
      DBAdvGrid4.AddButton(7,DBAdvGrid4.Row,50,15,'Bestellen',TCellHAlign(2),TCellVAlign(2));
    end;
  Ersatzteil_Dataset.Next;
  end;

end;
Da sich die Daten in dem Grid ändern und somit evtl. auch der Bestell Status muss immer erst geschaut werden ob der Button gezeichnet werden muss oder eben nicht.

Wen ich mir die Prozedur auf einen Knopf lege ist alles inordnung.
Möchte ich allerdings diese Prozedur in der Datasource beim OnChange aufrufen stürzt das Programm immer ab und gibt die Meldung "Stack Überlauf".
Ich könnte mir vorstellen, dass die Datasource noch nicht bereit ist oder noch irgendwelche Aufgaben erledigen muss aber wie kann ich Abfragen ob dem so ist?
Bzw. wie kann ich generell dieses Problem lösen?
Gruß Chris

DeddyH 1. Dez 2013 11:00

AW: Stack Überlauf fehler
 
Du meinst vermutlich TDatasource.OnDataChange? Das wird auch ausgelöst, wenn sich der aktive Datensatz ändert. Da Du die Datenmenge durchläufst, wird das also ausgelöst, durchläuft die Datenmenge, wird wieder ausgelöst und durchläuft die Datenmenge etc. pp.

himitsu 1. Dez 2013 11:03

AW: Stack Überlauf fehler
 
Rate mal, was OnChange OnDataChange macht, wenn deine Funktion anfängt durch das DataSet zu Scrollen?

Tipp: Haltepunkt auf den Start deiner Funktion und dann schön mit F7 durchsteppen.



PS:
Zitat:

Delphi-Quellcode:
if Ersatzteil_DatasetBestellt.Value=True then

Lass' diese Vergleiche mit True und False
und verwende
Delphi-Quellcode:
if x then
und
Delphi-Quellcode:
if not x then
.




Reicht es nicht, wenn du nur einmal durchscrollst und in einem durchgang die Buttons hinzufügst?
Oder müssen die unbedingt nacheinander sein.

Perlsau 1. Dez 2013 11:51

AW: Stack Überlauf fehler
 
Da ist offenbar vieles im Argen:

1. Man prüft Boolsche Ausdrücke nicht auf True! Eine Abfrage, ob ein Ausdruck wahr oder falsch ist, sieht folgendermaßen aus:
Delphi-Quellcode:
  if Ersatzteil_DatasetBestellt.Value then
  begin
    TuDiesUndDas;
    TuDasAuchNoch;
  end else
  begin
    TuWasAnderes;
    TuNochWasAnderes;
  end;
2. Mit diesem Konstrukt ist es nun auch nicht mehr nötig, die ganze Tabelle zweimal zu durchlaufen, da ein Boolean-Wert entweder wahr oder falsch ist und für beide Fälle entsprechende Methoden bereitgestellt werden.

3. Wenn du eine Ereignisbehandlung schreibst, in der das Ereignis, für das du diese Procedure schreibst, aufgerufen werden kann, ohne daß eine Abbruchbedingung definiert wurde, mußt du dich nicht wundern, wenn das einen Stack-Überlauf zur Folge hat. Recursive Programmierung erfordert also immer eine Abbruchbedingung.

4. Was möchtest du wirklich erreichen?

Offenbar hast du ein DBGrid, das eine Tabelle mit Artikeln darstellt. Nun möchtest du jedesmal, wenn der Anwender einen Datensatz selektiert, prüfen, ob für diesen Artikel eine Bestellung vorliegt (wozu auch immer). Liegt keine Bestellung vor, soll, wie ich das verstanden habe, ein Button sichtbar werden, mit dem man eine solche Bestellung vornehmen kann. Und diesen Button möchtest du, wie es scheint, in einer Spalte des DBGrids erscheinen lassen? Wieso eigentlich?

Ich würde hier einen Button unterhalb oder neben dem DBGrid platzieren, der je nach Zustand der entsprechenden Spalte (Value?) enabled oder disabled ist. In der Ereignisbehandlungsmethode AfterScroll deines Datasets löst du nun ein Ereignis aus, das den betreffenden Button je nach Zustand der entsprechenden Spalte auf verfügbar (enabled := true) oder nicht verfügbar setzt.

Es ist also nicht notwendig, beim Wechseln des Datensatz-Zeigers jedesmal die ganze Tabelle zu durchlaufen, denn du möchtest ja nur diesen einen Datensatz überprüfen.

Drumbo 2. Dez 2013 05:46

AW: Stack Überlauf fehler
 
Morgen und danke für die Antworten.

Ja war bisschen schlampig implementiert. Ja hab auch das onDataChange Ereignis gemeint. Sorry für die ungenauigkeit, kommt nicht mehr vor.


Zu der Logik bzw. Notwendigkeit des mehrmaligen Durchlaufen dieser Datenbank:

Ich habe verschieden Geräte bzw. Reparaturen denen ich verschiedene Ersatzteile hinzufügen möchte aber auch löschen. Desweiteren kann man innerhalb dieses Forms zu anderen Geräten bzw. Reparaturaufträgen scrollen. Ich hatte halt die Idee die Knöpfe immer dann zu zeichenen (bzw. löschen) wenn sich was ändert. Ich könnte jetzt auch alle Eventualitäten und möglichen Triggerzeitpunkte raussuchen und dort dann überprüfen ob die Knöpfe gezeichnet werden müssen oder nicht. Fände es aber beim OnDataChange besser.
Das mit dem Rekursiven aufruf leuchtet ein.
Hab jetzt eine Wartemarke erstellt und blocke den Zugriff während die Datenbank durchlaufen wird.

Danke für die schnelle und gute Hilfe.
Zur Komplettierung hier nochmal der ordentliche Code:wink:
Delphi-Quellcode:
procedure TAuftrag_form.BestellbtnCreate();
var
i:integer;
begin
  busy :=true;

   Ersatzteil_Dataset.First;
while not Ersatzteil_Dataset.Eof do
  begin
    if Ersatzteil_DatasetBestellt.Value then
    begin
      DBAdvGrid4.RemoveButton(7,DBAdvGrid4.Row);
    end else
    begin
      DBAdvGrid4.AddButton(7,DBAdvGrid4.Row,50,15,'Bestellen',TCellHAlign(2),TCellVAlign(2));
    end;
     Ersatzteil_Dataset.Next;
  end;

  busy:=false;

end;

Furtbichler 2. Dez 2013 06:22

AW: Stack Überlauf fehler
 
Ah, die Buttons sind in jeder Zeile des Ersatzteil-Grids...
So kann man das auch lösen. So wie Persau das gelöst hat, ist es aber einfacher.

Also: Dein Ersatzteil-Grid und dadrunter/drüber/neben ein (1!) Button 'btBestellen'.

Im OnDataChange-Ereignis des ErsatzTeil-Datasets dann:
Delphi-Quellcode:
Procedure TMyForm.ErsartTeilSourceDataChange(Sender: TObject; Field: TField);
Begin
  if Field=nil then
    btBestellen.Enabled := Not Ersatzteil_DatasetBestellt.AsBoolean;
End;
Fertig.
Wenn Field=nil, dann wird die Zeile gewechselt. Der Button verändert seinen Status also genau dann, wenn eine neue Zeile im Grid ausgewählt wird und ist ausgegraut, wenn man das Teil nicht bestellen kann (weil schon bestellt) und normal, also drückbar, wenn nicht.

Die Tatsache, das ein Ersatzteil schon bestellt ist, visualisierst Du entweder, indem Du die Spalte 'Bestellt' als Checkbox anzeigst, oder aber, indem Du die ganze Zeile einfärbst (z.B. grün=bestellt). Das spart Platz, denn die Information 'bestellt' erkennt man nun direkt an der Farbe.

Drumbo 2. Dez 2013 09:06

AW: Stack Überlauf fehler
 
Wollte die Tatsache das das Ersatzteil bestellt ist eigentlich dadurch visualisieren das der Button verschwindet. Sprich man bestellt und der Button geht weg. An sich funktioniert das mit der while auch ganz gut. Hab halt nun das Problem, dass ich durch die Schleife immer an den letzten Datensatz springe. Das wiederum ist schön und gut wenn ich aus dem Grid rausbleibe und die Datasource quasi nicht veränder. TU ich dies jedoch zeigt das Grid mir nur noch unvollständige Ergebnisse an. Das liegt daran, dass ich den Datenbank Zeiger ja verschiebe und damit dann das OnDataChange auslöse. Jetzt stell ich mir die Frage ob es hilft, wenn ich in meiner bestellbtncreate procedure den aktuellen Zeiger Speicher und nachher zurück setze? Könnt ihr mir das sagen bzw. Wie Kriege ich den überhaupt gespeichert?
@ Furtbichler: überprüft deine procedur immer den aktuell geänderten Datensatz oder wie geht das

DeddyH 2. Dez 2013 09:18

AW: Stack Überlauf fehler
 
Ich habe es zwar nicht ganz verstanden, aber den aktuellen Datensatzzeiger kannst Du Dir mit Delphi-Referenz durchsuchenGetBookmark merken und mit Delphi-Referenz durchsuchenGotoBookmark wieder dorthin zurückkehren, sofern es sich nicht um eine unidirektionale Datenmenge handelt.

p80286 2. Dez 2013 12:34

AW: Stack Überlauf fehler
 
Zitat:

Zitat von Drumbo (Beitrag 1238144)
Wollte die Tatsache das das Ersatzteil bestellt ist eigentlich dadurch visualisieren das der Button verschwindet. Sprich man bestellt und der Button geht weg.
....
An sich funktioniert das mit der while auch ganz gut. Hab halt nun das Problem, dass ich durch die Schleife immer an den letzten Datensatz springe. Das wiederum ist schön und gut wenn ich aus dem Grid rausbleibe und die Datasource quasi nicht veränder. TU ich dies jedoch zeigt das Grid mir nur noch unvollständige Ergebnisse an. Das liegt daran, dass ich den Datenbank Zeiger ja verschiebe und damit dann das OnDataChange auslöse. Jetzt stell ich mir die Frage ob es hilft, wenn ich in meiner bestellbtncreate procedure den aktuellen Zeiger Speicher und nachher zurück setze? Könnt ihr mir das sagen bzw. Wie Kriege ich den überhaupt gespeichert?

Ich würde das im Prinzip so lösen, daß eine Bestellung (Update / Insert ..) an die Db geschickt wird und mit einem anschließenden Select werden die (hoffentlich) geänderten Daten zurück geholt.
Die Klimmzüge auf dem Client mögen zwar schön sein, sind meiner Meinung nach nicht zuverlässig und unnötig kompliziert.

Gruß
K-H

Perlsau 2. Dez 2013 15:24

AW: Stack Überlauf fehler
 
Zitat:

Zitat von p80286 (Beitrag 1238175)
... und mit einem anschließenden Select werden die (hoffentlich) geänderten Daten zurück geholt.

Ich weiß ja nicht, wie du das siehst, aber ich denke, daß Programme, die auf Hoffnung basieren, nicht wirklich gelungen sind :twisted:

himitsu 2. Dez 2013 16:12

AW: Stack Überlauf fehler
 
Zitat:

Zitat von Perlsau (Beitrag 1238203)
Ich weiß ja nicht, wie du das siehst, aber ich denke, daß Programme, die auf Hoffnung basieren, nicht wirklich gelungen sind :twisted:

Wurden nicht letztes Jahr von einigen älteren Raketen die Quellcodes veröffentlicht?
Ich glaub da waren auch gewisse Kommentare enhalten, so ala "Ich hoffe das funktioniert so". (zum Glück wussten die Astronauten nichts davon)

p80286 2. Dez 2013 16:18

AW: Stack Überlauf fehler
 
Naja meine Hoffnung bezog sich auf die Verbindung Client<->DB. da steckt man ja nicht so richtig drin. GGf. könnte man die NSA ja um ein Verbundungsprotokoll bitten.;-)

Gruß
K-H

Perlsau 2. Dez 2013 16:34

AW: Stack Überlauf fehler
 
Zitat:

Zitat von himitsu (Beitrag 1238218)
Wurden nicht letztes Jahr von einigen älteren Raketen die Quellcodes veröffentlicht?

... und ich dachte immer, Raketen seien Hardware ... man lernt doch nie aus ...

himitsu 2. Dez 2013 17:10

AW: Stack Überlauf fehler
 
Zitat:

Zitat von Perlsau (Beitrag 1238228)
... und ich dachte immer, Raketen seien Hardware ... man lernt doch nie aus ...

Ich meinte natürlich die Software in der Hardware. :angle2:

Wo kann mich mir eigentlich gratis bissl RAM downloaden?
Meiner wird langsam voll.

p80286 2. Dez 2013 17:14

AW: Stack Überlauf fehler
 
Zitat:

Zitat von himitsu (Beitrag 1238240)
Zitat:

Zitat von Perlsau (Beitrag 1238228)
... und ich dachte immer, Raketen seien Hardware ... man lernt doch nie aus ...

Ich meinte natürlich die Software in der Hardware. :angle2:

Heißt das jetzt nich Firmware:?:

Gruß
K-H

Drumbo 3. Dez 2013 14:35

AW: Stack Überlauf fehler
 
Danke für die vielen Hinweise. Hab mal nen Tag Abstand von dem Problem genommen ( neue Baustellen aufgemacht ;-) ) und jetzt klappt es.
Wünsche noch einen schönen Tag
Grüße

Für die Interessierten hier noch der Code:
Aufruf durch folgende Procedure
Delphi-Quellcode:
procedure TAuftrag_form.Ersatzteil_sourceDataChange(Sender: TObject;
  Field: TField);
begin
if Auftrag_form.Active then
  begin
  if not busy then

    begin
      BestellbtnCreate();
    end;

  end;

end;
und die Bearbeitung des Grids

Delphi-Quellcode:
procedure TAuftrag_form.BestellbtnCreate();
var
i:integer;
SavePlace: TBookmark;
begin
  busy :=true;
  SavePlace:=dbadvgrid4.DataSource.DataSet.GetBookmark;

    DBAdvGrid4.DataSource.DataSet.First;
     if DBAdvGrid4.DataSource.DataSet.Eof then
  begin
    DBAdvGrid4.RemoveButton(7,1);
  end else
  begin
    while not DBAdvGrid4.DataSource.DataSet.Eof do
      begin

        if Ersatzteil_DatasetBestellt.Value then
      begin
        DBAdvGrid4.RemoveButton(7,DBAdvGrid4.Row);
      end else
      begin
        DBAdvGrid4.AddButton(7,DBAdvGrid4.Row,50,15,'Bestellen',TCellHAlign(2),TCellVAlign(2));
      end;
      DBAdvGrid4.DataSource.DataSet.Next;
  end;
  end;

  DBAdvGrid4.DataSource.DataSet.GotoBookmark(SavePlace);
  busy:=false;


end;

himitsu 3. Dez 2013 14:49

AW: Stack Überlauf fehler
 
Ein Ressourcenschutzblock (Try-Finally) kann nie schaden.
> Wenn es in der Funktion knallt, dann wird dein busy nicht zurückgesetzt.

Und das
Delphi-Quellcode:
if busy then Exit;
hätte ich an den Anfang von BestellbtnCreate und nicht in Ersatzteil_sourceDataChange gemcht.


Alle Zeitangaben in WEZ +1. Es ist jetzt 18:11 Uhr.

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