Delphi-PRAXiS

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Object-Pascal / Delphi-Language (https://www.delphipraxis.net/32-object-pascal-delphi-language/)
-   -   Delphi Kompilierfehler bei während er Laufzeit erstellten Objekten (https://www.delphipraxis.net/187776-kompilierfehler-bei-waehrend-er-laufzeit-erstellten-objekten.html)

JulianBayer 2. Jan 2016 12:48

Delphi-Version: 7

Kompilierfehler bei während er Laufzeit erstellten Objekten
 
Liebe Delphi Gemeinde!,
ich bringe mir gerade selbst im Rahmen meiner Diplomarbeit das Programmieren für die Programmierung eines Titroprozessors bei, jedoch bin ich nun auf einen für mich unerklärlichen Fehler gestoßen ... ich hoffe einer von euch kann mir helfen: :)

Bei meinem Programm erstelle ich ComboBoxen und Edits, welche während der Laufzeit durch die Änderung eines SpinEdits aufgerufen werden.

Das eigenartige ist, dass ich wenn ich das Programm normal mit F9 ausführe nur ein Fehler auftritt wenn ich eine ComboBox auf die Items 3,4 od. 5 stelle was dazu führt, dass ein weiteres Edit created wird.
Wenn ich nun das SpinEdit increase oder decrease, dann folgt die Fehlermeldung: "Zugriffsverletzung in der Adresse 00000000".

Wenn ich aber die Routine einzeln durchlaufen lasse (F8) und ich dann zu dem Form komme wo diese Objekte erstellt werden läuft der Compiler alle Zeilen wie erwartet und ohne Fehlermeldung durch, auch die die den Items der Dropbox Namen zuweisen, doch dann sind die Dropboxen "Leer" und man kann nichts auswählen. :(

Die Edits weisen nie Fehler auf ^^

Ich hoffe ihr könnt mit meiner Beschreibung etwas anfangen!

Hier noch Quelltext von dem besprochenen Form:

Varriablendekl.:
Delphi-Quellcode:
var
  Form7: TForm7;
  GlobaleZahl: Word;
  AnalytEdit : Array of TEdit;
  MassloesungsEdit : Array of TEdit;
  MrzMassloesungsEdit : Array of TEdit;
  TitrationsartComboBox : Array of TComboBox;
  BestimmungsartComboBox : Array of TComboBox;
  {ÜbergangsArray für Form5}
  UeAr : Array of TAnaly;
  BestZ : Array of Word;
implementation
Prozedur zum erstellen (und davor löschen):
Delphi-Quellcode:
 SetLength(AnalytEdit, i+1);
 SetLength(MassloesungsEdit, i+1);
 SetLength(TitrationsartComboBox, i+1);
 SetLength(BestimmungsartComboBox, i+1);
 for x := 0 to i do
  begin
   AnalytEdit[x].Free;
   MassloesungsEdit[x].Free;
   TitrationsartComboBox[x].Free;
   BestimmungsartComboBox[x].Free;
  end;


 SetLength(MassloesungsEdit, i);
 SetLength(TitrationsartComboBox, i);
 SetLength(BestimmungsartComboBox, i);
 SetLength(AnalytEdit, i);
 for x := 0 to i-1 do
  begin
   BestimmungsartComboBox[x] := TComboBox.Create(Form7);
   BestimmungsartComboBox[x].Parent := Form7;
   BestimmungsartComboBox[x].Top := Grundy + x*42;
   BestimmungsartComboBox[x].Left := Grundx;
   BestimmungsartComboBox[x].Height := 24;
   BestimmungsartComboBox[x].Width := 145;
   BestimmungsartComboBox[x].Clear;
   BestimmungsartComboBox[x].Items.Append('Einzelbestimmung');
    if SpinEdit2.Value > 1 then
     begin
      BestimmungsartComboBox[x].Items.Append('Summenbestimmung');
     end;
   BestimmungsartComboBox[x].ItemIndex := 0;
   BestimmungsartComboBox[x].OnChange := BestimmungsartChange;

   TitrationsartComboBox[x] := TComboBox.Create(Form7);
   TitrationsartComboBox[x].Parent := Form7;
   TitrationsartComboBox[x].Top := Grundy + x*42;
   TitrationsartComboBox[x].Left := Grundx + 160;
   TitrationsartComboBox[x].Height := 24;
   TitrationsartComboBox[x].Width := 145;
   TitrationsartComboBox[x].Clear;
   TitrationsartComboBox[x].Items.Append('Titerstellung');
   TitrationsartComboBox[x].Items.Append('Direkte Titration');
   TitrationsartComboBox[x].Items.Append('Inverse Titration');
   TitrationsartComboBox[x].Items.Append('Indirekte Titration');      //
   TitrationsartComboBox[x].Items.Append('Rücktitration');            //
   TitrationsartComboBox[x].Items.Append('Substitutionstitration');    //
   TitrationsartComboBox[x].ItemIndex := 0;
   TitrationsartComboBox[x].OnChange := TitrationsartChange;

   MassloesungsEdit[x] := TEdit.Create(Form7);
   MassloesungsEdit[x].Parent := Form7;
   MassloesungsEdit[x].Top := Grundy + x*42;
   MassloesungsEdit[x].Left := Grundx + 320;
   MassloesungsEdit[x].Height := 24;
   MassloesungsEdit[x].Width := 121;
   MassloesungsEdit[x].Text := 'Maßlösung ' + IntToStr(x+1);

   AnalytEdit[x] := TEdit.Create(Form7);
   AnalytEdit[x].Parent := Form7;
   AnalytEdit[x].Top := 256 + x*42;                        
   AnalytEdit[x].Left := 24;
   AnalytEdit[x].Height := 24;
   AnalytEdit[x].Width := 121;
   AnalytEdit[x].Text := 'Analyt ' + IntToStr(x+1);
  end;
Erstellen der weiteren Edits wenn Item 3,4,5 ausgewählt:
Delphi-Quellcode:
procedure TForm7.TitrationsartChange(Sender: TObject);        //Titrationsart
 var i,SD,index : Word;
 begin
  for i := 0 to SpinEdit1.Value -1 do
   begin
    if Sender = TitrationsartComboBox[i] then
     begin
      index := i;                                                 //index = die Reihe von 0 bis 9
     end;
   end;
  SD := (Sender as TComboBox).ItemIndex;
  if SD > 2 then
   begin
    MrzMassloesungsEdit[index].Free;
    MrzMassloesungsEdit[index]:= TEdit.Create(Form7);
    MrzMassloesungsEdit[index].Parent := Form7;
    MrzMassloesungsEdit[index].Left := 644;
    MrzMassloesungsEdit[index].Width := 162;
    MrzMassloesungsEdit[index].Top := 256 + 42*index;
    MrzMassloesungsEdit[index].Text := 'Rücktitrationssubstanz ' + IntToStr(1+index);
   end else
   begin
    MrzMassloesungsEdit[index].Free;
   end;
 end;

Wieder Löschen:

Delphi-Quellcode:
procedure TForm7.SpinEdit1Change(Sender: TObject);  //Analysen
 var i: Word;
 begin
  ShowEdits(SpinEdit1.Value,168, 256);
  SetLength(MrzMassloesungsEdit,SpinEdit1.Value);
   for i := 0 to SpinEdit1.Value-1 do
    begin
     if MrzMassloesungsEdit[i].Text = '' then
      begin
      end
      else
       MrzMassloesungsEdit[i].Free;
      end;
    end;
Beste Grüße,
und danke im voraus
Julian Bayer

Dalai 2. Jan 2016 12:56

AW: Kompilierfehler bei während er Laufzeit erstellten Objekten
 
Ich bin mir ziemlich sicher, dass der Compiler eine Warnung bzgl. der Schleifenvariable i anzeigt, die nach dem Schleifendurchlauf undefiniert ist. Sofern der Compiler optimieren kann, kann eine for-Schleife durchaus auch rückwärts durchlaufen werden, i wäre danach wohl 0.

Oder kurz ausgedrückt: Das ist ein ganz heißes Eisen, eine Schleifenvariable zum Setzen der Länge eines Arrays zu benutzen (nachdem die Schleife durchlaufen wurde).

MfG Dalai

mkinzler 2. Jan 2016 12:59

AW: Kompilierfehler bei während er Laufzeit erstellten Objekten
 
Zudem sollte man immer von hinten löschen, denn das Entfernen eines Elements führt zur Änderung der oberen Grenze, welche später nicht mehr erreicht werden kann.

Delphi-Quellcode:
for x := i-1 downto 0 do

Sir Rufo 2. Jan 2016 13:17

AW: Kompilierfehler bei während er Laufzeit erstellten Objekten
 
Ich würde generell mal diesen Verhau ein wenig strukturierter angehen, dann wird es wesentlich einfacher.

Zum einen könntest du Frames verwenden oder dir entsprechende Panels zusammenbauen:
Delphi-Quellcode:
type
  TEditPanel = class( TCustomPanel )
  private
    FBestimmungsArtCombobox: TComboBox;
    function GetBestimmungsArt: string;
    procedure SetBestimmungsArt( const Value: string );
    function GetBestimmungsArtIndex: Integer;
    procedure SetBestimmungsArtIndex( const Value: Integer );
    function GetBestimmungsArten: TStrings;
    procedure SetBestimmungsArten( const Value: TStrings );
  public
    constructor Create( AOwner: TComponent ); override;
    property BestimmungsArt: string read GetBestimmungsArt write SetBestimmungsArt;
    property BestimmungsArtIndex: Integer read GetBestimmungsArtIndex write SetBestimmungsArtIndex;
    property BestimmungsArten: TStrings read GetBestimmungsArten write SetBestimmungsArten;
  end;

implementation

{ TEditPanel }

constructor TEditPanel.Create( AOwner: TComponent );
begin
  inherited;
  FBestimmungsArtCombobox       := TComboBox.Create( Self );
  FBestimmungsArtCombobox.Parent := Self;
end;

function TEditPanel.GetBestimmungsArt: string;
begin
  Result := FBestimmungsArtCombobox.Text;
end;

function TEditPanel.GetBestimmungsArten: TStrings;
begin
  Result := FBestimmungsArtCombobox.Items;
end;

function TEditPanel.GetBestimmungsArtIndex: Integer;
begin
  Result := FBestimmungsArtCombobox.ItemIndex;
end;

procedure TEditPanel.SetBestimmungsArt( const Value: string );
begin
  FBestimmungsArtCombobox.Text := Value;
end;

procedure TEditPanel.SetBestimmungsArten( const Value: TStrings );
begin
  FBestimmungsArtCombobox.Items := Value;
end;

procedure TEditPanel.SetBestimmungsArtIndex( const Value: Integer );
begin
  FBestimmungsArtCombobox.ItemIndex := Value;
end;

stahli 2. Jan 2016 13:20

AW: Kompilierfehler bei während er Laufzeit erstellten Objekten
 
Delphi-Quellcode:
procedure TForm7.TitrationsartChange(Sender: TObject); //Titrationsart
  var i,SD,index : Word;
  begin
   for i := 0 to SpinEdit1.Value -1 do
    begin
     if Sender = TitrationsartComboBox[i] then
      begin
       index := i; //index = die Reihe von 0 bis 9
      end;
    end;
   SD := (Sender as TComboBox).ItemIndex;
Hier könnte Index undefiniert sein, wenn Sender keiner der Combobox entspricht.
Erhältst Du beim compilieren Warnhinweise? Dann schau Dir diese mal an (anklicken + F1). Das hilft dann manchmal schon weiter.
In dem Fall könntest Du Index vor der Schleife -1 zuweisen.

Controls haben eine (frei verwendbare) Eigenschaft "Tag". Der könntest Du evtl. auch einen Wert zuweisen und dann später direkt darauf zugreifen.
Delphi-Quellcode:
procedure TForm7.TitrationsartChange(Sender: TObject); //Titrationsart
  var i,SD,index : Word;
  begin
    if Sender is TComboBox then
      Index := (Sender as TComboBox).Tag
    else
      Index := -1;

Wegen dem unterschiedlichen Verhalten von F9 und F8 kann man evtl. auch vermuten, dass Windows ein Focusproblem hat.
Wenn ein Control den Focus hat und man dieses löscht kann Windows u.U. dabei durcheinander kommen.
Kommentiere ggf. einfach mal testweise die MeineControls.Free; aus.
Die Controls müllen zwar dann den Speicher zu aber wenn das Problem dann nicht mehr auftritt, wird es am Focus liegen.
So hätte man schon mal eine Eingrenzung gefunden.

Grundsätzlich kannst Du in dem problematischen Bereich auch mal OutputDebugString('StelleXYZ'); einbauen.
So kannst Du nachvollziehen, welche Zeilen noch korrekt erreicht werden.

JulianBayer 2. Jan 2016 13:38

AW: Kompilierfehler bei während er Laufzeit erstellten Objekten
 
Also wirklich danke für eure Hilfe!!!! :DDDD
Habt mir alle sehr geholfen :)
Läuft schon wieder :)

Und entschuldigung für den "Verhau" :-D
Bin ein Chemiker der des nu ned ganzgemeistert hat :P

Lg und schönen Tag noch Julian Bayer

Luckie 2. Jan 2016 18:36

AW: Kompilierfehler bei während er Laufzeit erstellten Objekten
 
Offtopic. Jetzt wo du es sagst. Dein Ergebnis sieht wirklich aus wie eine Polymerase-Kettenreaktion. :mrgreen:

Ontopic: Auch wenn du nicht gleich eine eigene Klasse baust. Eine Unterteilung in separate Routinen kann auch schon viel helfen. Je übersichtlicher, desto einfacher ist es auch Fehler zu finden.


Alle Zeitangaben in WEZ +1. Es ist jetzt 18:13 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