Delphi-PRAXiS

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Algorithmen, Datenstrukturen und Klassendesign (https://www.delphipraxis.net/78-algorithmen-datenstrukturen-und-klassendesign/)
-   -   SIGSEGV Fehler bei Stringzuweisung (https://www.delphipraxis.net/167803-sigsegv-fehler-bei-stringzuweisung.html)

Noobmaster 19. Apr 2012 16:49

SIGSEGV Fehler bei Stringzuweisung
 
Hallo Leute!

Folgender Code erzeugt eine SIGSEGV-Fehlermeldung. Der Debugger springt dann in eine Funkion namens TWinControlHandleAllocated, was mir überhaupt nichts sagt.

Delphi-Quellcode:
      IntAltePunkte := StrToInt(LblPunkte1.Caption);
      IntNeuePunkte := IntAltePunkte + IntGeschossen;
      NeueAnzeige  := IntToStr(IntNeuePunkte);
      LblPunkte1.Caption := NeueAnzeige;
Das Problem taucht nur auf, wenn die Caption vorher eine negative Zahl angezeigt hat und jetzt eine positive anzeigen soll.
Zeigte die Caption vorher eine negative Zahl an, so erfolgt jede neue Zuweisung einen Fehler:


Delphi-Quellcode:
      IntAltePunkte := StrToInt(LblPunkte1.Caption);
      IntNeuePunkte := IntAltePunkte + IntGeschossen;
      NeueAnzeige  := IntToStr(IntNeuePunkte);
      LblPunkte1.Caption := '1';
Eine erneute Zuweisung einer negativen Zahlen erzeugt jedoch keinen Fehler:


Delphi-Quellcode:
      IntAltePunkte := StrToInt(LblPunkte1.Caption);
      IntNeuePunkte := IntAltePunkte + IntGeschossen;
      NeueAnzeige  := IntToStr(IntNeuePunkte);
      LblPunkte1.Caption := '-1';
Danke schonmal für die Hilfe :-).

DeddyH 19. Apr 2012 16:53

AW: SIGSEGV Fehler bei Stringzuweisung
 
Hat es einen Grund, dass Du VCL-Controls als Datenspeicher missbrauchst? Wenn Du Dir die Werte in entsprechenden Variablen merkst, damit rechnest und das Label lediglich zur Ausgabe benutzt, kommt der Fehler dann immer noch?

Noobmaster 19. Apr 2012 17:00

Missbrauch von Komponenten
 
Bin noch nicht so sauber im Programmieren xD. Aber es klingt plausibel :-).
Ich änder es mal und schreib zurück wie es funktioniert hat.
Danke für die schnelle Antwort.

Noobmaster 19. Apr 2012 17:13

AW: SIGSEGV Fehler bei Stringzuweisung
 
Verbesserter Code führt zum gleichen Fehler:
Delphi-Quellcode:
      Spieler1.Punkte := Spieler1.Punkte + IntGeschossen;
      LblPunkte1.Caption := IntToStr(Spieler1.Punkte); //Anzeige aktualisieren

DeddyH 19. Apr 2012 17:33

AW: SIGSEGV Fehler bei Stringzuweisung
 
Das kann ich hier mit meiner etwas betagten Lazarus-Version(0.9.28.2) auf Win7 32Bit nicht nachvollziehen.

Noobmaster 19. Apr 2012 17:39

AW: SIGSEGV Fehler bei Stringzuweisung
 
0.9.30.04 ist meine Versionsnummer. Kann das wirklich an der Version liegen?

DeddyH 19. Apr 2012 17:43

AW: SIGSEGV Fehler bei Stringzuweisung
 
Ich habe nicht die leisteste Ahnung, da ich kaum etwas mit Lazarus mache, sry. Allerdings kann ich mir das nur schwer vorstellen, es sollte dem Label doch egal sein, was es darstellt, solange das ein String ist.

Noobmaster 19. Apr 2012 17:57

AW: SIGSEGV Fehler bei Stringzuweisung
 
Also ich find es auch extrem merkwürdig, dass ein Label abschmiert, wenn man ihm '-1'als Caption zuweist :-D.

Assarbad 19. Apr 2012 22:34

AW: SIGSEGV Fehler bei Stringzuweisung
 
Zitat:

Zitat von Noobmaster (Beitrag 1162699)
0.9.30.04 ist meine Versionsnummer. Kann das wirklich an der Version liegen?

Zumindest nicht so wahrscheinlich an der Lazarus-Version wie an der FreePascal-Version die im Hintergrund werkelt.

Einerlei, wann genau rufst du diesen Code auf? Irgendwo im Konstruktor oder Destruktor? Es gibt da nämlich ein paar Spezialfälle wenn bspw. der Container noch nicht komplett erzeugt ist etc ...

Ich würde ganz stark empfehlen ein minimales Beispielprojekt, welches das Problem sichtbar macht, bereitzustellen. Erstens grenzt du es so ein und lernst was dabei und zweitens ist es weniger Rätselraten für die Forenten :glaskugel:

Noobmaster 20. Apr 2012 10:49

AW: SIGSEGV Fehler bei Stringzuweisung
 
Ich habe den Fehler durch ein kleines Programm simulieren wollen:
Delphi-Quellcode:
   Label1.Caption := '-1';
Label1.Caption := '1';
Damit bekomme ich den Fehler allerdings nicht.

Mein Projektcode führt zu dem Fehler, aber es ist noch etwas bizarrer geworden.
Nur das LblPunkte1 führt zu diesem Fehler, das LblPunkte2 nicht.
Delphi-Quellcode:
//------------------------------------------------
//Wechsel-----------------------------------------
//------------------------------------------------
procedure TFormMain.Wechsel();
var
   IntGeschossen : Integer;
   IntAufnahme:   Integer;
begin
   //Jetzige Aufnahme verarbeiten und Anzeigen aktualisieren
   IntGeschossen := IntEsLiegen - SpinEditBaelle.Value;
   //Neue Höchstserie?
   IntAufnahme  := StrToInt(LblAufnahme.Caption);
   if bSpieler1IstDran then //Welcher Spieler ist dran? -> Punkte addieren etc.
   begin
      Spieler1.Punkte := Spieler1.Punkte + IntGeschossen;
      LblPunkte1.Caption := IntToStr(Spieler1.Punkte); //Anzeige aktualisieren-> Fehler, wenn
      //die Anzeige vorher '-1' angezeigt hat und soll nun eine positive Zahl anzeigen
      SGridTab1.Cells[0,IntAufnahme] := LblAufnahme.Caption;
      SGridTab1.Cells[1,IntAufnahme] := IntToStr(IntGeschossen);
      SGridTab1.Cells[3,IntAufnahme] := IntToStr(Spieler1.Punkte);
      //Passt die nächste Aufnahme noch auf das Sheet oder muss eine neue Zeile angefügt werden?
      if SGridTab1.RowCount <= IntAufnahme + 1 then
      begin
         SGridTab1.RowCount := SGridTab1.RowCount + 1;
         SGridTab2.RowCount := SGridTab2.RowCount + 1;
         //Die Tabellen bei Überlauf scrollen
         SGridTab1.TopRow := SGridTab1.TopRow + 1;
         SGridTab2.TopRow := SGridTab2.TopRow + 1;
      end;
      //Neue Höchstserie?
      if IntGeschossen > Spieler1.Serie then Spieler1.Serie := IntGeschossen;
   end else
   begin
      Spieler2.Punkte := Spieler2.Punkte + IntGeschossen;
      LblPunkte2.Caption := IntToStr(Spieler2.Punkte); //Anzeige aktualisieren-> kein Fehler
      SGridTab2.Cells[0,IntAufnahme] := LblAufnahme.Caption;
      SGridTab2.Cells[1,IntAufnahme] := IntToStr(IntGeschossen);
      SGridTab2.Cells[3,IntAufnahme] := IntToStr(Spieler2.Punkte);
      LblAufnahme.Caption := IntToStr(IntAufnahme+1);
      //Neue Höchstserie?
      if IntGeschossen > Spieler2.Serie then Spieler2.Serie := IntGeschossen;
   end;

   //Nächste Aufnahme:
   bSpieler1IstDran := not bSpieler1IstDran; //Nächster Spieler ist dran
   IntEsLiegen := SpinEditBaelle.Value;
end;
Das ist die Prozedur, in die der Debugger hineinspringt. Aber ich weiß nicht, was das mit einer Scrollbar zu tun haben soll.
Delphi-Quellcode:
function TControlScrollBar.HandleAllocated: boolean;
begin
  Result := (FControl <> nil) and FControl.HandleAllocated;
end;

Noobmaster 20. Apr 2012 13:27

Lösung
 
Hallo Leute!

Wie so oft liegt der Fehler zwar an dieser Stelle, hat aber dort nicht seine Ursache. Ich habe längere Zeit gegrübelt, was eine Scrollbar mit dem Problem zu tun haben könnte.
Hier die eigentliche Fehlerquelle:
Delphi-Quellcode:
//------------------------------------------------
//LblPunkte1 Position korrigieren-----------------
//------------------------------------------------
procedure TFormMain.LblPunkte1Resize(Sender: TObject);
var
   A,B: Integer;
begin
   while LblPunkte1.Left + LblPunkte1.Width <> SGridTab1.Left + SGridTab1.Width do
   begin
      LblPunkte1.Left := LblPunkte1.Left - 1;
   end;
end;
Die Prozedur war ursprünglich dafür da, die Position des Labels zu korrigieren, wenn das Label 2-stellige (oder 3-stellige) Zahlen anzeigt, da sich hierbei die Breite verändert. Eine negative Zahl ist dabei ja praktisch eine 2-stellige. Dabei habe ich den Fall vergessen, dass (was zu meiner Verteidigung äußerst selten vorkommt in dem Programm) das Label wieder eine 1-stellige Zahl anzeigen können muss und dass dabei "Left" vergrößert werden muss.

Kurz: Das Label wird soweit nach links verschoben, bis die Scrollbar des Fensters (die man allerdings nie zu sehen bekommt) maximal ist -> Fehler.

Entschuldigung für die "Belästigung" und danke nochmal für die Hilfe :-).

Verbessert (es funktioniert):
Delphi-Quellcode:
//------------------------------------------------
//LblPunkte1 Position korrigieren-----------------
//------------------------------------------------
procedure TFormMain.LblPunkte1Resize(Sender: TObject);
var
   A,B: Integer;
begin
   while LblPunkte1.Left + LblPunkte1.Width <> SGridTab1.Left + SGridTab1.Width do
   begin
      A := LblPunkte1.Left + LblPunkte1.Width;
      B := SGridTab1.Left + SGridTab1.Width;
      if A > B then LblPunkte1.Left := LblPunkte1.Left - 1   //1-stellig auf mehrstellig
               else LblPunkte1.Left := LblPunkte1.Left + 1; //2-stellig auf 1-stellig
   end;
end;

Dalai 20. Apr 2012 13:39

AW: Lösung
 
Zitat:

Zitat von Noobmaster (Beitrag 1162832)
Die Prozedur war ursprünglich dafür da, die Position des Labels zu korrigieren, wenn das Label 2-stellige (oder 3-stellige) Zahlen anzeigt, da sich hierbei die Breite verändert.

Das lässt sich verhindern, indem man mit Format() eine entsprechende Formatierung des Strings vornimmt, in diesem Fall sinnvollerweise Leerzeichen voranstellen.

Beachte außerdem, dass Labels eine Eigenschaft AutoSize haben, die standardmäßig auf True steht, und dass man den Text von Labels ausrichten kann (links, zentriert, rechts). Und wie jedes Control haben Labels natürlich auch Anchors. Ich wüsste jetzt also nicht, warum man unbedingt die Positionierung eines Labels korrigieren müsste, nur weil sich dessen Beschriftung ändert.

MfG Dalai

Noobmaster 21. Apr 2012 00:01

Labelposition
 
Habe jetzt kein Foto hier, aber die Situation sieht in etwa so aus:
'1' ':' '1'
Die Zeichenketten stellen Captions von drei Labels dar.
'10'':' '1'
Da ich aber immer einen gleichmäßigen Abstand der Anzeigen haben will, hab ich die Position manuell korrigiert, da ich sonst keine Methode kenne...aber es funktioniert ja auch :-D

himitsu 21. Apr 2012 02:19

AW: Labelposition
 
Statt der While-Schleife würde ich auch noch zu einem mathematischen Wege raten.

Sei froh, daß das Label etwas optimiert wurde, so daß es sich nicht wirklich bei jedem Move neu zeichnet, sondern nur eine entsprechende Message hinterläßt, um sich demnächst neu zu zeichnen.
Bei anderen Komponenten kann es "unschön" werden, wenn man es öfters (als nötig) verschiebt.

PS: Man kann den Labels auch sagen, daß sie sich rechtsbündig ausrichten sollen.
Und wenn die Labels alle den selben Font+Size haben, warum dann nicht alles in ein Label machen? (die kennen auch mittig/zentriert)

Noobmaster 21. Apr 2012 21:38

AW: Labelposition
 
Zitat:

Zitat von himitsu (Beitrag 1162930)
Statt der While-Schleife würde ich auch noch zu einem mathematischen Wege raten.

Sei froh, daß das Label etwas optimiert wurde, so daß es sich nicht wirklich bei jedem Move neu zeichnet, sondern nur eine entsprechende Message hinterläßt, um sich demnächst neu zu zeichnen.
Bei anderen Komponenten kann es "unschön" werden, wenn man es öfters (als nötig) verschiebt.

PS: Man kann den Labels auch sagen, daß sie sich rechtsbündig ausrichten sollen.
Und wenn die Labels alle den selben Font+Size haben, warum dann nicht alles in ein Label machen? (die kennen auch mittig/zentriert)

Das sind einfache Kniffe, die man erst lernen muss :-). Aber danke, denn so lerne ich sie ^^.


Alle Zeitangaben in WEZ +1. Es ist jetzt 05:05 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 by Thomas Breitkreuz