![]() |
Aufruf neuer Typen in anderen Units
Aufruf neuer Typen in anderen Units
Einleitung: Ich bin mit der Weile ein fortgeschrittener Anfänger. Zwar kann ich neue Methode, Variablen und Formen miteinander Verknüpfen, aber wenn ich manchmal meine Fehler sehe, lache ich später selbst darüber. Nun geht es darum, eine neue Unit zu erstellen (schon geschehen) und einen neuen Typen zu kreieren. Ich kann darauf zugreifen, bekomme dennoch einen "SIGSEGV"-Error, einen Zugriffserror. Ich suche nach der Lösung seit 3 Tagen und arbeitete mich durch sämtliche Anleitungen, Themen, Foren und was es alles noch so gibt. Arbeiten tue ich mit Lazarus "0.9.30.2" und Win7 32bit. Überblick: Mein Projekt beinhaltet die Formen Form1 vom Typ TForm1 in mainunit.lfm bzw. mainunit.pas und Form2 vom Typ TForm2 in image.lfm bzw. image.pas. Außerdem beinhaltet mein Projekt die Unit kennzeichen.pas in denen TListe und TDatensatz deklariert sind. Problembeschreibung: In meiner mainunit.pas befindet sich
Delphi-Quellcode:
, welche von einer anderen Prozedur in mainunit.pas aufgerufen wird. Am Schluss des interface-Teils deklariere ich:
procedure TForm1.Search(SearchString: String);
Delphi-Quellcode:
Die Prozedur "Search" in mainunit.passieht im "implementation"-Teil wie folgt aus:
var
Form1: TForm1; isGo: Boolean; unsereListe: TListe;
Delphi-Quellcode:
Durch das Durchsteppen mit F7 erfuhr ich, dass er wie befohlen
procedure TForm1.Search(SearchString: String);
begin if (Length(SearchString) <> 0) and (SearchString <> Last01.Caption) then begin Form1.Enabled := False; StartProgressBar(25); Wait(3); ChangeLast(SearchString); unsereListe := unsereListe.create; unsereListe.dateieinlesen('kfz.csv', SearchString); if unsereListe.NotA = false then begin Output2.Caption := unsereListe.liste[unsereListe.anzahl].kennzeichen; Output4.Caption := unsereListe.liste[unsereListe.anzahl].ort; Output6.Caption := unsereListe.liste[unsereListe.anzahl].bundesland; Output8.Caption := unsereListe.liste[unsereListe.anzahl].sonder; end; while ProgressBar.Position <> 0 do Wait(2); Form1.Enabled := True; end; end;
Delphi-Quellcode:
ohne Probleme durchläuft und erst bei
constructor TListe.create;
begin anzahl := 0; NotA := false; end;
Delphi-Quellcode:
kläglich scheitert. Nach dem "SIGSEGV"-Error zeigt er mit die Zeile
procedure TListe.dateieinlesen (datname, suchKFZ: STRING);
begin try datname := extractfilepath(ParamStr(0)) + 'lib\kfz.csv'; CompleteFile := TStringList.Create; CompleteFile.LoadFromFile(datname); ... finally ... end; end;
Delphi-Quellcode:
an. Das heißt, er kommt erst gar nicht dazu,
CompleteFile := TStringList.Create;
Delphi-Quellcode:
durchzuführen.
CompleteFile.LoadFromFile(datname);
Ich habe mein Projekt auf ![]() P.S.: Während ich das Thema erstellt habe, fiel mir etwas auf. Ich verschob in kennzeichen.pas
Delphi-Quellcode:
in die
CompleteFile := TStringList.Create;
Delphi-Quellcode:
. Schon leif dies ohne Probleme. Aber es stockte nun bei
constructor TListe.create;
Delphi-Quellcode:
.
CompleteFile.LoadFromFile(datname);
Mit freundlichen Grüßen Caesar2012, der Moderne |
AW: Aufruf neuer Typen in anderen Units
Versuch mal:
Delphi-Quellcode:
EDIT: Du kannst auch an deinen Beitrag Dateien anhängen, dann bleiben die auch am Beitrag und verschwinden nicht, wenn der Hoster sich verabschiedet
constructor TListe.create;
begin inherited; // <--- das ist wichtig! anzahl := 0; NotA := false; end; |
AW: Aufruf neuer Typen in anderen Units
Danke für die schnelle Antwort. Was macht dieses
Delphi-Quellcode:
?
inherited;
Ich könnte das Projekt nicht anhängen, da es 17 MB groß war. Und in den nächsten Monaten verabschiedet er sich nicht, der ist seit Jaaahren online und mein Favorit, da ohne Schnickschnack. EDIT: Es funktioniert immer noch nicht. Nach dem Error meldet mir der Debugger beim Überfahren von
Delphi-Quellcode:
in TListe.dateieinlesen
CompleteFile := TStringList.Create;
"TStringList.Create = A syntax error in expression near `.Create` . |
AW: Aufruf neuer Typen in anderen Units
Zitat:
Zitat:
|
AW: Aufruf neuer Typen in anderen Units
Liste der Anhänge anzeigen (Anzahl: 1)
Wie schon oben gesagt, funktioniert es immer noch nicht. Danke für deine Antwort. Jetzt habe ich nur das nötigste und ohne Bilder als Anhang mein Projekt hinzugefügt.
MFG Caesar2011, der Moderne Falls ihr noch was benötigt, sagt es ruhig. |
AW: Aufruf neuer Typen in anderen Units
Sodele, ich habe dann mal die Unit entsprechend kommentiert und ausgebessert
Delphi-Quellcode:
Allerdings ist der wirkliche Fehler gar nicht in der Unit zu finden ;)
unit kennzeichen;
// {$mode objfpc}{$H+} interface uses SysUtils, Classes; // , Graphics, Controls, Forms, Dialogs, ExtCtrls; type TDatensatz = class kennzeichen : STRING; // Öffentliche Variable, die das "kennzeichnen" ausgibt Ort : STRING; // Öffentliche Variable, die den "ort" ausgibt Bundesland : STRING; // Öffentliche Variable, die das "bundesland" ausgibt Sonder : STRING; // Öffentliche Variable, die das "bundesland" ausgibt constructor Create; // Konstruktor von TDatensatz destructor Destroy; // Destruktor von TDatensatz procedure Einlesen( DatenString : STRING ); // Aufteilen von "datenstring" in "kennzeichen", "ort", "bundesland" function IstKennzeichen( KennzeichenString : STRING ) : BOOLEAN; // Boolean'sche Funktion, ob "kennzeichenstring" == "kennzeichen" end; TListe = class public Liste : ARRAY [1 .. 600] OF TDatensatz; // riesiges Array der kompletten *.csv des Types "TDatensatz" Anzahl : CARDINAL; // Nr. der aktuellen Zeile in der *.csv CompleteFile : TStringList; // Ganzes File als TStringList NotA : BOOLEAN; // Sagt aus, ob Input verfügbar constructor Create; // Konstruktor von TListe destructor Destroy; override; // Destruktor von TListe procedure DateiEinlesen( datname, suchKFZ : STRING ); // Einlesen und Verarbeiten der *.csv (LoadFileFrom, Erstellen von "liste") function Lesen( i : CARDINAL; datnamen : TStringList ) : TDatensatz; // Gibt einen result des Typen TDatensatz aus function GibAnzahl : CARDINAL; // Gibt Variable "anzahl" aus // aber wozu? die Variable kann man doch direkt auslesen, wozu nochmals eine function dafür? function NAcheck( j : INTEGER; Stringlist : TStringList ) : BOOLEAN; end; var unsereListe : TListe; implementation constructor TDatensatz.Create; begin inherited; // <-- fehlte kennzeichen := ''; Ort := ''; Bundesland := ''; Sonder := ''; end; destructor TDatensatz.Destroy; begin // überflüssig // kennzeichen := ''; // Ort := ''; // Bundesland := ''; // Sonder := ''; inherited; // <-- fehlte end; procedure TDatensatz.Einlesen( DatenString : STRING ); begin kennzeichen := Copy( DatenString, 1, pos( ';', DatenString ) - 1 ); Delete( DatenString, 1, pos( ';', DatenString ) ); Ort := Copy( DatenString, 1, pos( ';', DatenString ) - 1 ); Delete( DatenString, 1, pos( ';', DatenString ) ); Bundesland := DatenString; end; function TDatensatz.IstKennzeichen( KennzeichenString : STRING ) : BOOLEAN; begin Result := false; // <-- verschoben, da sonst immer False als Result if KennzeichenString = kennzeichen then Result := true; // result := false; end; constructor TListe.Create; begin inherited; Anzahl := 0; NotA := false; CompleteFile := TStringList.Create; // das muss hier hin end; destructor TListe.Destroy; var i : CARDINAL; begin if Anzahl > 0 then begin for i := 1 to Anzahl do Liste[i].Free; // nicht Destroy direkt aufrufen Anzahl := 0; end; NotA := false; CompleteFile.Free; // nicht Destroy direkt aufrufen inherited; // <-- fehlte end; procedure TListe.DateiEinlesen( datname, suchKFZ : STRING ); begin // try datname := extractfilepath( ParamStr( 0 ) ) + 'lib\kfz.csv'; // Nein, da gibt es schon eine Instanz // CompleteFile := TStringList.Create; CompleteFile.LoadFromFile( datname ); if NAcheck( Anzahl, CompleteFile ) then begin Lesen( Anzahl, CompleteFile ); if not Liste[Anzahl].IstKennzeichen( suchKFZ ) then begin Anzahl := GibAnzahl + 1; DateiEinlesen( datname, suchKFZ ); end else begin if Lesen( Anzahl, CompleteFile ).Bundesland = '' then begin Liste[Anzahl].Sonder := Liste[Anzahl].Bundesland; Liste[Anzahl].Bundesland := ''; Liste[Anzahl].Ort := ''; end; end; end; // und diese Instanz bleibt // finally // CompleteFile.Free; // end; end; function TListe.Lesen( i : CARDINAL; datnamen : TStringList ) : TDatensatz; begin Liste[i].Einlesen( datnamen.Strings[i] ); Result := Liste[i]; end; function TListe.GibAnzahl : CARDINAL; begin Result := Anzahl; end; function TListe.NAcheck( j : INTEGER; Stringlist : TStringList ) : BOOLEAN; begin Result := false; // <-- verschoben, da sonst immer False als Result if j <= Stringlist.Count then Result := true; NotA := true; // Result := false; end; end. sondern hier:
Delphi-Quellcode:
procedure TForm1.Search( SearchString : String );
begin if ( Length( SearchString ) <> 0 ) and ( SearchString <> Last01.Caption ) then begin Form1.Enabled := False; StartProgressBar( 25 ); Wait( 3 ); ChangeLast( SearchString ); // hier war der Haupt-Fehler unsereListe := TListe.Create; // statt unsereListe.create try unsereListe.dateieinlesen( 'kfz.csv', SearchString ); if not unsereListe.NotA // statt unsereListe.NotA = False then begin Output2.Caption := unsereListe.liste[unsereListe.anzahl].kennzeichen; Output4.Caption := unsereListe.liste[unsereListe.anzahl].ort; Output6.Caption := unsereListe.liste[unsereListe.anzahl].bundesland; Output8.Caption := unsereListe.liste[unsereListe.anzahl].sonder; end; finally unsereListe.Free; // freigeben, sonst gibt das ein riesen Speicherleck end; // Geduldsprobe für den User, es passiert nichts, ausser dass der Balken sich bewegt while ProgressBar.Position <> 0 do Wait( 2 ); Form1.Enabled := True; end; end;
|
AW: Aufruf neuer Typen in anderen Units
Danke, dass du dir so viel Zeit gelassen hast. Ich werde es begutachten!!
Gibt es hier im Forum ein "User-Like"-Buuton? :-D Bei den ganzen Fehlern wird mir schwindelig. Den
Delphi-Quellcode:
und alles andere mit
destructor TDatensatz.destroy;
Delphi-Quellcode:
habe ich ausder Schule, wo wie das Projetzt aus Zeitgründen niedergelegt haben.
destroy;
Ach und zur Geduldsprobe: Weil ich's kann! ;-) EDIT: Jetzt bekomme ich zumindest kein Error. Nur leider kommt kein Output auf dem Feld. Ich schau mir mal den Debugger an. |
AW: Aufruf neuer Typen in anderen Units
Delphi-Quellcode:
Der Destructor Destroy muss mit "override" überschrieben werden, damit dieser auch von Free benutzt wird.
TDatensatz = class
{...} destructor destroy; override; {...} end; In dieser Klasse ist der constructor überflüssig, da Stringvariablen einer Klasse automatisch leer, Interfaces und Pointer nil und numerische Variablen mit 0 initialisiert werden. Diese Hinweise gelten z.T. auch für deine anderen Klassen.
Delphi-Quellcode:
Sinnvoller ist hier ein dymamisches Array oder TObjectList.
Liste : ARRAY [1 .. 600] OF TDatensatz;
Delphi-Quellcode:
Das Laden und Speichern direkt im Datenobjekt zu implementieren ist keine gute Idee.
// String-Parameter nach Möglichkeit als const übergeben, kann der Compiler besser optimieren.
function TDatensatz.istKennzeichen(const kennzeichenstring:STRING):BOOLEAN; begin // Vergleiche ergeben bereits einen Boolean-Wert // if (True) then // Result := True // else // Result := False; // den man auch einer Variablen oder dem Rückgabewert direkt zuweisen kann. Result := (kennzeichenstring = kennzeichen); end; Hier bietet sich z.B. das Visitor-Pattern an. ![]() |
AW: Aufruf neuer Typen in anderen Units
Danke auch dir. Nur bei dem destroy von
Delphi-Quellcode:
hasbe ich Probleme.
destructor TListe.destroy;
Aufgerufen wird er mit
Delphi-Quellcode:
in mainunit.pas, nachdem alles fertig ist.
unsereListe.destroy;
Ich glaube es hat teilweise auch was mit dem anderen Destruktor
Delphi-Quellcode:
zu tun. Sir Rufo half mir schon per PN, aber ich konnte keine wiederholte Zerstörung feststellen. Außerdem bin ich mir mit dem override sowie dem Unterschied von free/freeandnil/destoy nicht im Klaren. Wann benutze ich
destructor TDatensatz.destroy;
Delphi-Quellcode:
bei Destuktoren und wann nicht? Wann benutze ich
override:
Delphi-Quellcode:
,
.Free
Delphi-Quellcode:
und wann
.FreeAndNil
Delphi-Quellcode:
?
.Destroy
Delphi-Quellcode:
destructor TListe.destroy;
var i:CARDINAL; begin if anzahl > 0 then begin for i := 1 to anzahl do liste[i].free; anzahl := 0; end; NotA := false; CompleteFile.free; inherited; end;
Delphi-Quellcode:
destructor TDatensatz.destroy;
begin kennzeichen := ''; ort := ''; bundesland := ''; sonder := ''; inherited; end; |
AW: Aufruf neuer Typen in anderen Units
Der Destruktor Destroy sollte immer überschrieben werden. Ein direkter Aufruf ist zu vermeiden, stattdessen Free verwenden, welches vorher auf nil prüft. FreeAndNil verwendet man dann, wenn es möglich sein kann, dass nach dem Freigeben evtl. noch auf die (nun nicht mehr vorhandene) Instanz zugegriffen werden könnte. Somit kann man auf nil prüfen.
|
Alle Zeitangaben in WEZ +1. Es ist jetzt 11:47 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