Upload
others
View
23
Download
0
Embed Size (px)
Citation preview
Embarcadero Delphi
#delphi
Inhaltsverzeichnis
Über 1
Kapitel 1: Erste Schritte mit Embarcadero Delphi 2
Bemerkungen 2
Versionen 2
Examples 3
Hallo Welt 3
Zeigen Sie "Hello World" mithilfe der VCL 4
Show 'Hello World' mit WinAPI MessageBox 4
Plattformübergreifende Hello World mit FireMonkey 4
Kapitel 2: Aktualisierte TDataSet-Daten in einem Hintergrundthread abrufen 6
Bemerkungen 6
Examples 6
FireDAC-Beispiel 6
Kapitel 3: Andere Programme ausführen 9
Examples 9
CreateProcess 9
Kapitel 4: Animationen in Firemonkey verwenden 11
Examples 11
Rotierender Dreieck 11
Kapitel 5: Einen Thread ausführen, während die GUI ansprechend bleibt 12
Examples 12
Responsive GUI mit Threads für die Hintergrundarbeit und PostMessage zum Berichten von Thr 12
Faden 12
Bilden 14
Kapitel 6: Für Loops 16
Syntax 16
Bemerkungen 16
Examples 16
Einfach für die Schleife 16
Zeichen einer Zeichenfolge durchlaufen 17
Umkehrung der Schleife 17
Für eine Schleife mit einer Aufzählung 18
Für in Reihe 18
Kapitel 7: Generics 20
Examples 20
Sortieren Sie ein dynamisches Array mit dem generischen TArray.Sort 20
Einfache Verwendung von TList 20
Absteigend von TList es spezifisch machen 20
Sortieren Sie eine TList 21
Kapitel 8: Leicht entfernbare Laufzeitfehlerprüfungen erstellen 22
Einführung 22
Examples 22
Triviales Beispiel 22
Kapitel 9: Schleifen 24
Einführung 24
Syntax 24
Examples 24
Brechen Sie in Loops und fahren Sie fort 24
Wiederhole bis 25
Während tun 25
Kapitel 10: Schnittstellen 27
Bemerkungen 27
Examples 27
Schnittstelle definieren und implementieren 27
Implementierung mehrerer Schnittstellen 28
Vererbung für Schnittstellen 28
Eigenschaften in Schnittstellen 29
Kapitel 11: TStringList-Klasse 31
Examples 31
Einführung 31
Schlüsselwertpaarung 31
Kapitel 12: Verwendung von RTTI in Delphi 34
Einführung 34
Bemerkungen 34
Examples 34
Grundlegende Klasseninformationen 34
Kapitel 13: Verwendung von try außer und zum Schluss 36
Syntax 36
Examples 36
Einfaches try..finally Beispiel, um Speicherlecks zu vermeiden 36
Ausnahmesichere Rückgabe eines neuen Objekts 36
Try-endlich verschachtelt in Try-Exceptions 37
Try-Ausnahme verschachtelt in Try-finally 37
Try-finally mit 2 oder mehr Objekten 38
Kapitel 14: Zeichenketten 39
Examples 39
String-Typen 39
Zeichenketten 39
Zeichen 40
Groß-und Kleinschreibung 40
Zuordnung 40
Referenzzählung 41
Kodierungen 41
Kapitel 15: Zeitintervallmessung 43
Examples 43
Verwenden der Windows-API GetTickCount 43
TStopwatch-Datensatz verwenden 43
Credits 45
Über
You can share this PDF with anyone you feel could benefit from it, downloaded the latest version from: embarcadero-delphi
It is an unofficial and free Embarcadero Delphi ebook created for educational purposes. All the content is extracted from Stack Overflow Documentation, which is written by many hardworking individuals at Stack Overflow. It is neither affiliated with Stack Overflow nor official Embarcadero Delphi.
The content is released under Creative Commons BY-SA, and the list of contributors to each chapter are provided in the credits section at the end of this book. Images may be copyright of their respective owners unless otherwise specified. All trademarks and registered trademarks are the property of their respective company owners.
Use the content presented in this book at your own risk; it is not guaranteed to be correct nor accurate, please send your feedback and corrections to [email protected]
https://riptutorial.com/de/home 1
Kapitel 1: Erste Schritte mit Embarcadero Delphi
Bemerkungen
Delphi ist eine Universalsprache, die auf einem Object Pascal-Dialekt basiert, dessen Wurzeln von Borland Turbo Pascal stammen. Es wird mit einer eigenen IDE geliefert, die die schnelle Anwendungsentwicklung (RAD) unterstützt.
Es ermöglicht die plattformübergreifende native (kompilierte) Anwendungsentwicklung aus einer einzigen Codebasis. Derzeit werden folgende Plattformen unterstützt: Windows, OSX, iOS und Android.
Es gibt zwei visuelle Rahmenbedingungen:
VCL: Visual Component Library, die speziell für die Windows-Entwicklung entwickelt wurde und native Steuerelemente von Windows umschließt.
•
FMX: FireMonkey-Plattformübergreifendes Framework für alle unterstützten Plattformen•
Versionen
AusführungNumerische Version
Produktname Veröffentlichungsdatum
1 1,0 Borland Delphi 1995-02-14
2 2,0 Borland Delphi 2 1996-02-10
3 3,0 Borland Delphi 3 1997-08-05
4 4,0 Borland Delphi 4 1998-07-17
5 5,0 Borland Delphi 5 1999-08-10
6 6,0 Borland Delphi 6 2001-05-21
7 7,0 Borland Delphi 7 2002-08-09
8 8,0 Borland Delphi 8 für .NET 2003-12-22
2005 9,0 Borland Delphi 2005 2004-10-12
2006 10,0 Borland Delphi 2006 2005-11-23
2007 11,0 CodeGear Delphi 2007 2007-03-16
https://riptutorial.com/de/home 2
AusführungNumerische Version
Produktname Veröffentlichungsdatum
2009 12,0 CodeGear Delphi 2009 2008-08-25
2010 14,0Embarcadero RAD Studio 2010
2009-08-15
XE 15,0Embarcadero RAD Studio XE
2010-08-30
XE2 16,0Embarcadero RAD Studio XE2
2011-09-02
XE3 17,0Embarcadero RAD Studio XE3
2012-09-03
XE4 18,0Embarcadero RAD Studio XE4
2013-04-22
XE5 19,0Embarcadero RAD Studio XE5
2013-09-11
XE6 20,0Embarcadero RAD Studio XE6
2014-04-15
XE7 21,0Embarcadero RAD Studio XE7
2014-09-02
XE8 22,0Embarcadero RAD Studio XE8
2015-04-07
10 Seattle 23,0Embarcadero RAD Studio 10 Seattle
2015-08-31
10.1 Berlin 24,0Embarcadero RAD Studio 10.1 Berlin
2016-04-20
10.2 Tokio 25,0Embarcadero RAD Studio 10.2 Tokio
2017-03-22
Examples
Hallo Welt
Dieses Programm, das in einer Datei mit dem Namen HelloWorld.dpr gespeichert ist, wird in eine Konsolenanwendung übersetzt, die "Hello World" an die Konsole druckt:
https://riptutorial.com/de/home 3
program HelloWorld; {$APPTYPE CONSOLE} begin WriteLn('Hello World'); end.
Zeigen Sie "Hello World" mithilfe der VCL
Dieses Programm verwendet VCL, die standardmäßige UI-Komponentenbibliothek von Delphi, um "Hello World" in ein Meldungsfeld zu drucken. Die VCL umschließt die meisten häufig verwendeten WinAPI-Komponenten. Auf diese Weise können sie viel einfacher verwendet werden, z. B. ohne dass Sie mit Fenstergriffen arbeiten müssen.
Um eine Abhängigkeit aufzunehmen (wie in diesem Fall Vcl.Dialogs ), fügen Sie den uses einschließlich einer durch Kommas getrennten Liste von Einheiten hinzu, die mit einem Semikolon enden.
program HelloWindows; uses Vcl.Dialogs; begin ShowMessage('Hello Windows'); end.
Show 'Hello World' mit WinAPI MessageBox
Dieses Programm verwendet die Windows-API (WinAPI), um "Hello World" in ein Meldungsfeld zu drucken.
Um eine Abhängigkeit aufzunehmen (wie in diesem Fall Windows ), fügen Sie den Anwendungsblock einschließlich einer durch Kommas getrennten Liste von Einheiten hinzu, die mit einem Semikolon enden.
program HelloWorld; uses Windows; begin MessageBox(0, 'Hello World!', 'Hello World!', 0); end.
Plattformübergreifende Hello World mit FireMonkey
XE2
program CrossPlatformHelloWorld;
https://riptutorial.com/de/home 4
uses FMX.Dialogs; {$R *.res} begin ShowMessage('Hello world!'); end.
Die meisten von Delphi unterstützten Plattformen (Win32 / Win64 / OSX32 / Android32 / iOS32 / iOS64) unterstützen auch eine Konsole, sodass das WriteLn Beispiel gut zu ihnen passt.
Für die Plattformen, für die eine GUI erforderlich ist (jedes iOS-Gerät und einige Android-Geräte), funktioniert das obige FireMonkey-Beispiel gut.
Erste Schritte mit Embarcadero Delphi online lesen: https://riptutorial.com/de/delphi/topic/599/erste-schritte-mit-embarcadero-delphi
https://riptutorial.com/de/home 5
Kapitel 2: Aktualisierte TDataSet-Daten in einem Hintergrundthread abrufen
Bemerkungen
Dieses FireDAC-Beispiel und die anderen, die ich einreichen möchte, vermeiden die Verwendung nativer Aufrufe zum asynchronen Öffnen der Datenmenge.
Examples
FireDAC-Beispiel
Das folgende Codebeispiel zeigt eine Möglichkeit, Datensätze von einem MSSQL-Server in einem Hintergrundthread mithilfe von FireDAC abzurufen. Getestet für Delphi 10 Seattle
Wie geschrieben:
Der Thread ruft Daten mit seiner eigenen TFDConnection und TFDQuery ab und überträgt die Daten in einem Aufruf von Sychronize () an die FDQuery des Formulars.
•
Die Ausführung ruft die Daten nur einmal ab. Es kann geändert werden, um die Abfrage wiederholt als Antwort auf eine vom VCL-Thread bereitgestellte Nachricht auszuführen.
•
Code:
type TForm1 = class; TFDQueryThread = class(TThread) private FConnection: TFDConnection; FQuery: TFDQuery; FForm: TForm1; published constructor Create(AForm : TForm1); destructor Destroy; override; procedure Execute; override; procedure TransferData; property Query : TFDQuery read FQuery; property Connection : TFDConnection read FConnection; property Form : TForm1 read FForm; end; TForm1 = class(TForm) FDConnection1: TFDConnection; FDQuery1: TFDQuery; DataSource1: TDataSource; DBGrid1: TDBGrid; DBNavigator1: TDBNavigator; Button1: TButton;
https://riptutorial.com/de/home 6
procedure FormDestroy(Sender: TObject); procedure Button1Click(Sender: TObject); procedure FormCreate(Sender: TObject); private public QueryThread : TFDQueryThread; end; var Form1: TForm1; implementation {$R *.dfm} { TFDQueryThread } constructor TFDQueryThread.Create(AForm : TForm1); begin inherited Create(True); FreeOnTerminate := False; FForm := AForm; FConnection := TFDConnection.Create(Nil); FConnection.Params.Assign(Form.FDConnection1.Params); FConnection.LoginPrompt := False; FQuery := TFDQuery.Create(Nil); FQuery.Connection := Connection; FQuery.SQL.Text := Form.FDQuery1.SQL.Text; end; destructor TFDQueryThread.Destroy; begin FQuery.Free; FConnection.Free; inherited; end; procedure TFDQueryThread.Execute; begin Query.Open; Synchronize(TransferData); end; procedure TFDQueryThread.TransferData; begin Form.FDQuery1.DisableControls; try if Form.FDQuery1.Active then Form.FDQuery1.Close; Form.FDQuery1.Data := Query.Data; finally Form.FDQuery1.EnableControls; end; end; procedure TForm1.FormDestroy(Sender: TObject); begin QueryThread.Free; end;
https://riptutorial.com/de/home 7
procedure TForm1.Button1Click(Sender: TObject); begin if not QueryThread.Finished then QueryThread.Start else ShowMessage('Thread already executed!'); end; procedure TForm1.FormCreate(Sender: TObject); begin FDQuery1.Open; QueryThread := TFDQueryThread.Create(Self); end; end.
Aktualisierte TDataSet-Daten in einem Hintergrundthread abrufen online lesen: https://riptutorial.com/de/delphi/topic/4114/aktualisierte-tdataset-daten-in-einem-hintergrundthread-abrufen
https://riptutorial.com/de/home 8
Kapitel 3: Andere Programme ausführen
Examples
CreateProcess
Die folgende Funktion kapselt Code für die Verwendung von CreateProcess Windows API zum Starten anderer Programme.
Es ist konfigurierbar und kann warten, bis der aufrufende Prozess abgeschlossen ist oder sofort zurückkehrt.
Parameter:
FileName - vollständiger Pfad zur ausführbaren Datei•Params - Befehlszeilenparameter oder leere Zeichenfolge verwenden•Folder - Arbeitsordner für das aufgerufene Programm - wenn aus FileName leerer Pfad extrahiert FileName
•
WaitUntilTerminated - wenn die Funktion true wartet, bis der Prozess die Ausführung beendet hat
•
WaitUntilIdle - Wenn die Funktion true die Funktion WaitForInputIdle aufruft , und warten, bis der angegebene Prozess die Verarbeitung seiner ursprünglichen Eingabe abgeschlossen hat und keine Benutzereingaben vorliegen
•
RunMinimized - wenn der Prozess "True" minimiert ausgeführt wird•ErrorCode - Wenn die Funktion fehlschlägt, enthält sie den gefundenen Windows-Fehlercode•
function ExecuteProcess(const FileName, Params: string; Folder: string; WaitUntilTerminated, WaitUntilIdle, RunMinimized: boolean; var ErrorCode: integer): boolean; var CmdLine: string; WorkingDirP: PChar; StartupInfo: TStartupInfo; ProcessInfo: TProcessInformation; begin Result := true; CmdLine := '"' + FileName + '" ' + Params; if Folder = '' then Folder := ExcludeTrailingPathDelimiter(ExtractFilePath(FileName)); ZeroMemory(@StartupInfo, SizeOf(StartupInfo)); StartupInfo.cb := SizeOf(StartupInfo); if RunMinimized then begin StartupInfo.dwFlags := STARTF_USESHOWWINDOW; StartupInfo.wShowWindow := SW_SHOWMINIMIZED; end; if Folder <> '' then WorkingDirP := PChar(Folder) else WorkingDirP := nil; if not CreateProcess(nil, PChar(CmdLine), nil, nil, false, 0, nil, WorkingDirP, StartupInfo, ProcessInfo) then begin Result := false;
https://riptutorial.com/de/home 9
ErrorCode := GetLastError; exit; end; with ProcessInfo do begin CloseHandle(hThread); if WaitUntilIdle then WaitForInputIdle(hProcess, INFINITE); if WaitUntilTerminated then repeat Application.ProcessMessages; until MsgWaitForMultipleObjects(1, hProcess, false, INFINITE, QS_ALLINPUT) <> WAIT_OBJECT_0 + 1; CloseHandle(hProcess); end; end;
Verwendung der obigen Funktion
var FileName, Parameters, WorkingFolder: string; Error: integer; OK: boolean; begin FileName := 'C:\FullPath\myapp.exe'; WorkingFolder := ''; // if empty function will extract path from FileName Parameters := '-p'; // can be empty OK := ExecuteProcess(FileName, Parameters, WorkingFolder, false, false, false, Error); if not OK then ShowMessage('Error: ' + IntToStr(Error)); end;
CreateProcess-Dokumentation
Andere Programme ausführen online lesen: https://riptutorial.com/de/delphi/topic/5180/andere-programme-ausfuhren
https://riptutorial.com/de/home 10
Kapitel 4: Animationen in Firemonkey verwenden
Examples
Rotierender Dreieck
Erstellen Sie eine leere Multi-Device-Anwendung (Firemonkey).1. Drop Rechteck auf Formular.2. Im Objektinspektorfenster (F11) finden Sie RotationAngle. Klicken Sie auf die Dropdown-Schaltfläche und wählen Sie "Neue TFloatAnimation erstellen".
3.
Das Objektinspektorfenster wird automatisch auf eine neu hinzugefügte TFloatAnimation umgestellt. Sie können es auch im Strukturmenü anzeigen (Umschalttaste + Alt)
F11).•
4.
Füllzeit im Objektinspektor von TFloatAnimation mit einer beliebigen Anzahl (in Sekunden). In unserem Fall nehmen wir Folgendes: 1. Lassen Sie die StartValue-Eigenschaft unverändert, und geben Sie in StopValue den Typ - 360 (Grad, damit alles rund läuft). Wir können auch die Loop-Option aktivieren (diese Animation wird so lange durchlaufen, bis sie vom Code angehalten wird).
5.
Jetzt haben wir unsere Animation eingerichtet. Es bleibt nur noch, es einzuschalten: Lassen Sie zwei Schaltflächen auf das Formular fallen, rufen Sie zuerst "Start" und dann "Stop" an. in OnClick-Ereignis der ersten Schaltfläche schreiben:
FloatAnimation1.Start;
OnClick des zweiten Tastencodes:
FloatAnimation1.Stop;
Wenn Sie den Namen Ihrer TFloatAnimation geändert haben - Ändern Sie diesen auch, wenn Sie Start und Stop aufrufen.
Führen Sie nun Ihr Projekt aus, klicken Sie auf die Schaltfläche "Start" und genießen Sie es.
Animationen in Firemonkey verwenden online lesen: https://riptutorial.com/de/delphi/topic/5383/animationen-in-firemonkey-verwenden
https://riptutorial.com/de/home 11
Kapitel 5: Einen Thread ausführen, während die GUI ansprechend bleibt
Examples
Responsive GUI mit Threads für die Hintergrundarbeit und PostMessage zum Berichten von Threads
Um eine GUI während eines langwierigen Prozesses reaktionsfähig zu halten, sind entweder sehr aufwendige "Rückrufe" erforderlich, um der GUI die Verarbeitung ihrer Nachrichtenwarteschlange zu ermöglichen, oder die Verwendung von (Hintergrund) (Worker) -Threads.
Es ist normalerweise kein Problem, eine beliebige Anzahl von Threads zu starten, um einige Arbeit zu erledigen. Der Spaß beginnt, wenn Sie die GUI Zwischen- und Endergebnisse anzeigen oder über den Fortschritt berichten möchten.
Das Anzeigen von Elementen in der GUI erfordert die Interaktion mit Steuerelementen und / oder der Nachrichtenwarteschlange / -pumpe. Dies sollte immer im Kontext des Hauptthreads erfolgen. Niemals im Zusammenhang mit einem anderen Thread.
Es gibt viele Möglichkeiten, damit umzugehen.
Dieses Beispiel zeigt, wie Sie dies mit einfachen Threads tun können. Dadurch kann die GUI auf die Thread-Instanz zugreifen, nachdem sie fertig ist, indem Sie FreeOnTerminate auf false und melden, wenn ein Thread mit PostMessage "fertig" PostMessage .
Hinweise zu den Rennbedingungen: Verweise auf die Arbeitsthreads werden im Formular in einem Array gespeichert. Wenn ein Thread abgeschlossen ist, wird die entsprechende Referenz im Array auf Null gesetzt.
Dies ist eine potenzielle Quelle für Rennbedingungen. Die Verwendung eines booleschen Typs "Running" erleichtert die Feststellung, ob noch Threads vorhanden sind, die abgeschlossen werden müssen.
Sie müssen entscheiden, ob Sie diese Ressource mit Sperren schützen müssen oder nicht.
In diesem Beispiel ist es so, wie es ist, keine Notwendigkeit. Sie werden nur an zwei Stellen geändert: der StartThreads Methode und der HandleThreadResults Methode. Beide Methoden laufen immer nur im Kontext des Hauptthreads. Solange Sie es auf diese Weise beibehalten und diese Methoden nicht aus dem Kontext verschiedener Threads aufrufen, gibt es für sie keine Möglichkeit, Race-Bedingungen zu erzeugen.
Faden
type
https://riptutorial.com/de/home 12
TWorker = class(TThread) private FFactor: Double; FResult: Double; FReportTo: THandle; protected procedure Execute; override; public constructor Create(const aFactor: Double; const aReportTo: THandle); property Factor: Double read FFactor; property Result: Double read FResult; end;
Der Konstruktor setzt nur die privaten Mitglieder und setzt FreeOnTerminate auf False. Dies ist wichtig, da der Haupt-Thread die Thread-Instanz nach seinem Ergebnis abfragen kann.
Die Ausführungsmethode führt ihre Berechnung aus und sendet dann eine Nachricht an das Handle, das sie in ihrem Konstruktor erhalten hat, um zu sagen, dass sie fertig ist:
procedure TWorker.Execute; const Max = 100000000;var i : Integer; begin inherited; FResult := FFactor; for i := 1 to Max do FResult := Sqrt(FResult); PostMessage(FReportTo, UM_WORKERDONE, Self.Handle, 0); end;
Die Verwendung von PostMessage ist in diesem Beispiel unerlässlich. PostMessage "nur" eine Nachricht in die Warteschlange der Nachrichtenpumpe des Hauptthreads ein und wartet nicht darauf, dass sie verarbeitet wird. Es ist asynchron in der Natur. Wenn Sie SendMessage verwenden SendMessage , würden Sie sich selbst in eine Pickle codieren. SendMessage legt die Nachricht in die Warteschlange und wartet, bis sie verarbeitet wurde. Kurz gesagt, es ist synchron.
Die Deklarationen für die benutzerdefinierte UM_WORKERDONE-Nachricht werden wie folgt deklariert:
const UM_WORKERDONE = WM_APP + 1; type TUMWorkerDone = packed record Msg: Cardinal; ThreadHandle: Integer; unused: Integer; Result: LRESULT; end;
Die UM_WORKERDONE verwendet WM_APP als Ausgangspunkt für ihren Wert, um sicherzustellen, dass keine von Windows oder der Delphi-VCL (von MicroSoft empfohlen ) verwendeten Werte
https://riptutorial.com/de/home 13
beeinträchtigt werden.
Bilden
Jedes Formular kann zum Starten von Threads verwendet werden. Sie müssen lediglich die folgenden Mitglieder hinzufügen:
private FRunning: Boolean; FThreads: array of record Instance: TThread; Handle: THandle; end; procedure StartThreads(const aNumber: Integer); procedure HandleThreadResult(var Message: TUMWorkerDone); message UM_WORKERDONE;
Oh, und der Beispielcode setzt die Existenz eines Memo1: TMemo; in den Deklarationen des Formulars, die es für "Protokollierung und Berichterstellung" verwendet.
Mit dem FRunning kann verhindert werden, dass die GUI während der Arbeit angeklickt wird. FThreads wird verwendet, um den Instanzzeiger und das Handle der erstellten Threads zu halten.
Die Prozedur zum Starten der Threads ist ziemlich unkompliziert. Es beginnt mit einer Prüfung, ob bereits ein Satz Threads gewartet wird. Wenn ja, wird es einfach beendet. Ist dies nicht der Fall, wird das Flag auf true gesetzt und die Threads werden mit einem eigenen Handle versehen, sodass sie wissen, wo sie ihre "Fertig" -Meldung posten sollen.
procedure TForm1.StartThreads(const aNumber: Integer); var i: Integer; begin if FRunning then Exit; FRunning := True; Memo1.Lines.Add(Format('Starting %d worker threads', [aNumber])); SetLength(FThreads, aNumber); for i := 0 to aNumber - 1 do begin FThreads[i].Instance := TWorker.Create(pi * (i+1), Self.Handle); FThreads[i].Handle := FThreads[i].Instance.Handle; end; end;
Das Handle des Threads wird auch in das Array eingefügt, weil wir dies in den Nachrichten erhalten, die uns sagen, dass ein Thread fertiggestellt ist. Wenn er sich außerhalb der Instanz des Threads befindet, ist der Zugriff etwas einfacher. Wenn das Handle außerhalb der Instanz des Threads verfügbar ist, können wir auch FreeOnTerminate auf True setzen, wenn die Instanz nicht benötigt wurde, um die Ergebnisse zu erhalten (z. B. wenn sie in einer Datenbank gespeichert wurden). In diesem Fall wäre es natürlich nicht nötig, einen Hinweis auf die Instanz zu führen.
https://riptutorial.com/de/home 14
Der Spaß liegt in der HandleThreadResult-Implementierung:
procedure TForm1.HandleThreadResult(var Message: TUMWorkerDone); var i: Integer; ThreadIdx: Integer; Thread: TWorker; Done: Boolean; begin // Find thread in array ThreadIdx := -1; for i := Low(FThreads) to High(FThreads) do if FThreads[i].Handle = Cardinal(Message.ThreadHandle) then begin ThreadIdx := i; Break; end; // Report results and free the thread, nilling its pointer and handle // so we can detect when all threads are done. if ThreadIdx > -1 then begin Thread := TWorker(FThreads[i].Instance); Memo1.Lines.Add(Format('Thread %d returned %f', [ThreadIdx, Thread.Result])); FreeAndNil(FThreads[i].Instance); FThreads[i].Handle := nil; end; // See whether all threads have finished. Done := True; for i := Low(FThreads) to High(FThreads) do if Assigned(FThreads[i].Instance) then begin Done := False; Break; end; if Done then begin Memo1.Lines.Add('Work done'); FRunning := False; end; end;
Diese Methode sucht zuerst den Thread anhand des in der Nachricht empfangenen Handles. Wenn eine Übereinstimmung gefunden wurde, ruft es das Ergebnis des Threads mit der Instanz ab ( FreeOnTerminate war False , erinnern Sie sich daran?) Und meldet das Ergebnis des Threads. Anschließend wird es beendet: Die Instanz wird FreeOnTerminate und der FreeOnTerminate und das Handle auf null gesetzt länger relevant.
Zum Schluss wird geprüft, ob noch Threads laufen. Wenn keine gefunden wird, wird "all done" gemeldet und das FRunning Flag auf " False " gesetzt, damit ein neuer Arbeitsstapel gestartet werden kann.
Einen Thread ausführen, während die GUI ansprechend bleibt online lesen: https://riptutorial.com/de/delphi/topic/1796/einen-thread-ausfuhren--wahrend-die-gui-ansprechend-bleibt
https://riptutorial.com/de/home 15
Kapitel 6: Für Loops
Syntax
für OrdinalVariable: = LowerOrdinalValue bis UpperOrdinalValue fangen das Ende von {Schleifenkörper} an;
•
für OrdinalVariable: = UpperOrdinalValue Abwärts bis LowerOrdinalValue fangen das Ende von {Schleifenkörper} an;
•
für EnumerableVariable in Collection begin {Loop-Body} end;•
Bemerkungen
Die for -loop-Syntax von Delphi bietet keine Möglichkeit, die Schrittmenge von 1 auf einen anderen Wert zu ändern.
•
Beim Schleifen mit variablen Ordinalwerten, z. B. lokalen Variablen vom Typ Integer , werden die oberen und unteren Werte nur einmal bestimmt. Änderungen an solchen Variablen haben keine Auswirkung auf die Anzahl der Schleifeniterationen.
•
Examples
Einfach für die Schleife
Eine for Schleife wiederholt sich vom Anfangswert bis zum Endwert.
program SimpleForLoop; {$APPTYPE CONSOLE} var i : Integer; begin for i := 1 to 10 do WriteLn(i); end.
Ausgabe:
1 2 3 4 5 6 7 8 9
https://riptutorial.com/de/home 16
10
Zeichen einer Zeichenfolge durchlaufen
2005
Im Folgenden werden die Zeichen der Zeichenfolge s durchlaufen. Es funktioniert auf ähnliche Weise für das Schleifen der Elemente eines Arrays oder einer Gruppe, solange der Typ der Schleifensteuervariablen (in diesem Beispiel c ) dem Elementtyp des iterierten Werts entspricht.
program ForLoopOnString; {$APPTYPE CONSOLE} var s : string; c : Char; begin s := 'Example'; for c in s do WriteLn(c); end.
Ausgabe:
E x ein m p l e
Umkehrung der Schleife
Eine for Schleife durchläuft vom Startwert bis zum Endwert (als Beispiel "Countdown").
program CountDown; {$APPTYPE CONSOLE} var i : Integer; begin for i := 10 downto 0 do WriteLn(i); end.
Ausgabe:
10 9
https://riptutorial.com/de/home 17
8 7 6 5 4 3 2 1 0
Für eine Schleife mit einer Aufzählung
Eine for Schleife durchläuft Elemente in einer Aufzählung
program EnumLoop; uses TypInfo; type TWeekdays = (Sunday, Monday, Tuesday, Wednesday, Thursday, Friday, Saturday); var wd : TWeekdays; begin for wd in TWeekdays do WriteLn(GetEnumName(TypeInfo(TWeekdays), Ord(wd))); end.
Ausgabe:
Sonntag Montag Dienstag Mittwoch Donnerstag Freitag Samstag
Für in Reihe
Eine for Schleife durchläuft Elemente in einem Array
program ArrayLoop; {$APPTYPE CONSOLE} const a : array[1..3] of real = ( 1.1, 2.2, 3.3 ); var f : real; begin for f in a do WriteLn( f );
https://riptutorial.com/de/home 18
end.
Ausgabe:
1,1 2,2 3,3
Für Loops online lesen: https://riptutorial.com/de/delphi/topic/4643/fur-loops
https://riptutorial.com/de/home 19
Kapitel 7: Generics
Examples
Sortieren Sie ein dynamisches Array mit dem generischen TArray.Sort
uses System.Generics.Collections, { TArray } System.Generics.Defaults; { TComparer<T> } var StringArray: TArray<string>; { Also works with "array of string" } ... { Sorts the array case insensitive } TArray.Sort<string>(StringArray, TComparer<string>.Construct( function (const A, B: string): Integer begin Result := string.CompareText(A, B); end ));
Einfache Verwendung von TList
var List: TList<Integer>; ... List := TList<Integer>.Create; { Create List } try List.Add(100); { Add Items } List.Add(200); WriteLn(List[1]); { 200 } finally List.Free; end;
Absteigend von TList es spezifisch machen
type TIntegerList = class(TList<Integer>) public function Sum: Integer; end; ... function TIntegerList.Sum: Integer; var Item: Integer; begin Result := 0;
https://riptutorial.com/de/home 20
for Item in Self do Result := Result + Item; end;
Sortieren Sie eine TList
var List: TList<TDateTime>; ... List.Sort( TComparer<TDateTime>.Construct( function(const A, B: TDateTime): Integer begin Result := CompareDateTime(A, B); end ) );
Generics online lesen: https://riptutorial.com/de/delphi/topic/4054/generics
https://riptutorial.com/de/home 21
Kapitel 8: Leicht entfernbare Laufzeitfehlerprüfungen erstellen
Einführung
Dies zeigt, wie eine selbst erstellte Laufzeitfehlerüberprüfungsroutine problemlos integriert werden kann, sodass beim Ausschalten kein Code-Overhead entsteht.
Examples
Triviales Beispiel
{$DEFINE MyRuntimeCheck} // Comment out this directive when the check is no-longer required! // You can also put MyRuntimeCheck in the project defines instead. function MyRuntimeCheck: Boolean; {$IFNDEF MyRuntimeCheck} inline; {$ENDIF} begin result := TRUE; {$IFDEF MyRuntimeCheck} // .. the code for your check goes here {$ENDIF} end;
Das Konzept ist im Grunde Folgendes:
Das definierte Symbol wird verwendet, um die Verwendung des Codes zu aktivieren. Dadurch wird auch verhindert, dass der Code explizit eingebettet wird, sodass es einfacher ist, einen Haltepunkt in die Prüfroutine einzufügen.
Allerdings ist die wahre Schönheit dieser Konstruktion , wenn Sie die Prüfung wollen nicht mehr. Durch das Auskommentieren des $ DEFINE (setzen Sie "//" davor), entfernen Sie nicht nur den Prüfcode, sondern schalten auch die Inline für die Routine ein und entfernen so alle Overheads an allen Stellen, an denen Sie aufgerufen haben die Routine! Der Compiler entfernt alle Spuren Ihrer Prüfung vollständig (vorausgesetzt natürlich, dass das Inlining auf "Ein" oder "Auto" gesetzt ist).
Das obige Beispiel ist im Wesentlichen dem Konzept der "Assertions" ähnlich, und Ihre erste Zeile könnte das Ergebnis entsprechend der Verwendung auf TRUE oder FALSE setzen.
Sie können diese Konstruktionsweise jetzt aber auch für Code verwenden, der Traceprotokollierung, Metriken usw. durchführt. Zum Beispiel:
procedure MyTrace(const what: string); {$IFNDEF MyTrace} inline; {$ENDIF} begin {$IFDEF MyTrace} // .. the code for your trace-logging goes here {$ENDIF}
https://riptutorial.com/de/home 22
end; ... MyTrace('I was here'); // This code overhead will vanish if 'MyTrace' is not defined. MyTrace( SomeString ); // So will this.
Leicht entfernbare Laufzeitfehlerprüfungen erstellen online lesen: https://riptutorial.com/de/delphi/topic/10541/leicht-entfernbare-laufzeitfehlerprufungen-erstellen
https://riptutorial.com/de/home 23
Kapitel 9: Schleifen
Einführung
Delphi-Sprache bietet 3 Arten von Schleifen
for - iterator für feste Reihenfolge über Ganzzahl, String, Array oder Aufzählung
repeat-until - Quit-Bedingung wird nach jeder Runde geprüft, wobei die Schleife mindestens einmal ausgeführt wird
while do do-Bedingung vor jeder Runde überprüft wird, kann die Schleife niemals ausgeführt werden
Syntax
für OrdinalVariable: = LowerOrdinalValue bis UpperOrdinalValue fangen das Ende von {Schleifenkörper} an;
•
für OrdinalVariable: = UpperOrdinalValue Abwärts bis LowerOrdinalValue fangen das Ende von {Schleifenkörper} an;
•
für EnumerableVariable in Collection begin {Loop-Body} end;•wiederholen Sie {loop-body} bis {break-condition};•while {Bedingung} begin {Endet {Loop-Body};•
Examples
Brechen Sie in Loops und fahren Sie fort
program ForLoopWithContinueAndBreaks; {$APPTYPE CONSOLE} var var i : integer; begin for i := 1 to 10 do begin if i = 2 then continue; (* Skip this turn *) if i = 8 then break; (* Break the loop *) WriteLn( i ); end; WriteLn('Finish.'); end.
Ausgabe:
1 3
https://riptutorial.com/de/home 24
4 5 6 7 Fertig.
Wiederhole bis
program repeat_test; {$APPTYPE CONSOLE} var s : string; begin WriteLn( 'Type a words to echo. Enter an empty string to exit.' ); repeat ReadLn( s ); WriteLn( s ); until s = ''; end.
Dieses kurze Beispiel wird auf der Konsole gedruckt. Geben Sie Type a words to echo. Enter an empty string to exit. , warten Sie auf den Benutzertyp, wiederholen Sie die Echo-Eingabe und warten Sie die Eingabe in einer Endlosschleife erneut ab - bis der Benutzer den leeren String eingibt.
Während tun
program WhileEOF; {$APPTYPE CONSOLE} uses SysUtils; const cFileName = 'WhileEOF.dpr'; var F : TextFile; s : string; begin if FileExists( cFileName ) then begin AssignFile( F, cFileName ); Reset( F ); while not Eof(F) do begin ReadLn(F, s); WriteLn(s); end; CloseFile( F ); end else WriteLn( 'File ' + cFileName + ' not found!' ); end.
In diesem Beispiel wird der Textinhalt der WhileEOF.dpr Datei mit der While not(EOF) Bedingung
https://riptutorial.com/de/home 25
While not(EOF) WhileEOF.dpr . Wenn die Datei leer ist, wird die ReadLn-WriteLn Schleife nicht ausgeführt.
Schleifen online lesen: https://riptutorial.com/de/delphi/topic/9931/schleifen
https://riptutorial.com/de/home 26
Kapitel 10: Schnittstellen
Bemerkungen
Schnittstellen werden verwendet, um die benötigten Informationen und die erwartete Ausgabe von Methoden und Klassen zu beschreiben, ohne Informationen über die explizite Implementierung bereitzustellen.
Klassen können Schnittstellen implementieren , und Schnittstellen können voneinander erben . Wenn eine Klasse eine Schnittstelle implementiert , bedeutet dies, dass alle von der Schnittstelle bereitgestellten Funktionen und Prozeduren in der Klasse vorhanden sind.
Ein besonderer Aspekt von Interfaces in Delphi ist, dass Instanzen von Interfaces über ein Lebensdauermanagement verfügen, das auf der Referenzzählung basiert. Die Lebensdauer von Klasseninstanzen muss manuell verwaltet werden.
Unter Berücksichtigung all dieser Aspekte können Schnittstellen verwendet werden, um verschiedene Ziele zu erreichen:
Mehrere verschiedene Implementierungen für Operationen bereitstellen (z. B. Speichern in einer Datei, Datenbank oder Senden als E-Mail, alle als Schnittstelle "SaveData")
•
Reduzieren Sie Abhängigkeiten, verbessern Sie die Entkopplung und machen Sie so den Code besser wartbar und überprüfbar
•
Arbeiten Sie mit Instanzen in mehreren Einheiten, ohne sich durch das Lifetime-Management zu stören (obwohl auch hier Fallstricke vorhanden sind, passen Sie auf!)
•
Examples
Schnittstelle definieren und implementieren
Eine Schnittstelle wird wie eine Klasse deklariert, jedoch ohne Zugriffsmodifizierer ( public , private , ...). Außerdem sind keine Definitionen zulässig, daher können Variablen und Konstanten nicht verwendet werden.
Schnittstellen sollten immer über eine eindeutige Kennung verfügen, die durch Drücken von Strg + Umschalttaste + G generiert werden kann.
IRepository = interface ['{AFCFCE96-2EC2-4AE4-8E23-D4C4FF6BBD01}'] function SaveKeyValuePair(aKey: Integer; aValue: string): Boolean; end;
Um eine Schnittstelle zu implementieren, muss der Name der Schnittstelle hinter der Basisklasse hinzugefügt werden. Außerdem sollte die Klasse ein Nachkomme von TInterfacedObject (dies ist wichtig für die Lebenszeitverwaltung ).
https://riptutorial.com/de/home 27
TDatabaseRepository = class(TInterfacedObject, IRepository) function SaveKeyValuePair(aKey: Integer; aValue: string): Boolean; end;
Wenn eine Klasse eine Schnittstelle implementiert, muss sie alle in der Schnittstelle deklarierten Methoden und Funktionen enthalten. Andernfalls wird sie nicht kompiliert.
Bemerkenswert ist, dass Zugriffsmodifizierer keinen Einfluss haben, wenn der Anrufer mit der Schnittstelle arbeitet. Zum Beispiel können alle Funktionen der Schnittstelle als strict private Member implementiert werden, sie können jedoch auch von einer anderen Klasse aufgerufen werden, wenn eine Instanz der Schnittstelle verwendet wird.
Implementierung mehrerer Schnittstellen
Klassen können mehr als eine Schnittstelle implementieren, anstatt von mehreren Klassen zu erben ( Multiple Inheritance ), was für Delphi-Klassen nicht möglich ist. Um dies zu erreichen, muss der Name aller Schnittstellen durch Kommas getrennt hinter der Basisklasse hinzugefügt werden.
Natürlich muss die implementierende Klasse auch die von jeder der Schnittstellen deklarierten Funktionen definieren.
IInterface1 = interface ['{A2437023-7606-4551-8D5A-1709212254AF}'] procedure Method1(); function Method2(): Boolean; end; IInterface2 = interface ['{6C47FF48-3943-4B53-8D5D-537F4A0DEC0D}'] procedure SetValue(const aValue: TObject); function GetValue(): TObject; property Value: TObject read GetValue write SetValue; end; TImplementer = class(TInterfacedObject, IInterface1, IInterface2) // IInterface1 procedure Method1(); function Method2(): Boolean; // IInterface2 procedure SetValue(const aValue: TObject); function GetValue(): TObject property Value: TObject read GetValue write SetValue; end;
Vererbung für Schnittstellen
Schnittstellen können voneinander erben, genau wie Klassen auch. Eine implementierende Klasse muss also Funktionen der Schnittstelle und aller Basisschnittstellen implementieren. Auf diese Weise weiß der Compiler jedoch nicht, dass die implizierende Klasse auch die Basisschnittstelle
https://riptutorial.com/de/home 28
implementiert. Er kennt nur die explizit aufgeführten Schnittstellen. Aus diesem Grund würde die Verwendung as ISuperInterface auf TImplementer nicht funktionieren. Dies führt in der üblichen Praxis auch dazu, alle Basisschnittstellen explizit zu implementieren (in diesem Fall TImplementer = class(TInterfacedObject, IDescendantInterface, ISuperInterface) ).
ISuperInterface = interface ['{A2437023-7606-4551-8D5A-1709212254AF}'] procedure Method1(); function Method2(): Boolean; end; IDescendantInterface = interface(ISuperInterface) ['{6C47FF48-3943-4B53-8D5D-537F4A0DEC0D}'] procedure SetValue(const aValue: TObject); function GetValue(): TObject; property Value: TObject read GetValue write SetValue; end; TImplementer = class(TInterfacedObject, IDescendantInterface) // ISuperInterface procedure Method1(); function Method2(): Boolean; // IDescendantInterface procedure SetValue(const aValue: TObject); function GetValue(): TObject property Value: TObject read GetValue write SetValue; end;
Eigenschaften in Schnittstellen
Da die Deklaration von Variablen in Schnittstellen nicht möglich ist, kann die "schnelle" Art der Definition von Eigenschaften ( property Value: TObject read FValue write FValue; ) nicht verwendet werden. Stattdessen müssen auch Getter und Setter (jeweils nur bei Bedarf) in der Schnittstelle deklariert werden.
IInterface = interface(IInterface) ['{6C47FF48-3943-4B53-8D5D-537F4A0DEC0D}'] procedure SetValue(const aValue: TObject); function GetValue(): TObject; property Value: TObject read GetValue write SetValue; end;
Bemerkenswert ist, dass die implementierende Klasse die Eigenschaft nicht deklarieren muss. Der Compiler würde diesen Code akzeptieren:
TImplementer = class(TInterfacedObject, IInterface) procedure SetValue(const aValue: TObject); function GetValue(): TObject end;
https://riptutorial.com/de/home 29
Ein Nachteil ist jedoch, dass auf diese Eigenschaft nur über eine Instanz der Schnittstelle zugegriffen werden kann, nicht über die Klasse selbst. Durch das Hinzufügen der Eigenschaft zur Klasse wird außerdem die Lesbarkeit erhöht.
Schnittstellen online lesen: https://riptutorial.com/de/delphi/topic/4885/schnittstellen
https://riptutorial.com/de/home 30
Kapitel 11: TStringList-Klasse
Examples
Einführung
TStringList ist ein Nachkomme der TStrings-Klasse der VCL. TStringList kann zum Speichern und Bearbeiten von Strings verwendet werden. Obwohl ursprünglich für Strings vorgesehen, können mit dieser Klasse auch beliebige Objekttypen bearbeitet werden.
TStringList wird in VCL häufig verwendet, wenn der Zweck besteht, eine Liste von Strings zu verwalten. TStringList unterstützt eine Vielzahl von Methoden, die ein hohes Maß an Anpassung und einfache Handhabung bieten.
Das folgende Beispiel zeigt das Erstellen, Hinzufügen von Strings, das Sortieren, Abrufen und Freigeben eines TStringList-Objekts.
procedure StringListDemo; var MyStringList: TStringList; i: Integer; Begin //Create the object MyStringList := TStringList.Create(); try //Add items MyStringList.Add('Zebra'); MyStringList.Add('Elephant'); MyStringList.Add('Tiger'); //Sort in the ascending order MyStringList.Sort; //Output for i:=0 to MyStringList.Count - 1 do WriteLn(MyStringList[i]); finally //Destroy the object MyStringList.Free; end; end;
TStringList bietet eine Vielzahl von Benutzerfällen, einschließlich der Bearbeitung von Zeichenfolgen, dem Sortieren, der Indexierung, der Schlüsselwertpaarung und der Trennung von Trennzeichen.
Schlüsselwertpaarung
Sie können eine TStringList verwenden, um Schlüssel-Wert-Paare zu speichern. Dies kann
https://riptutorial.com/de/home 31
nützlich sein, wenn Sie beispielsweise Einstellungen speichern möchten. Eine Einstellung besteht aus einem Schlüssel (der ID der Einstellung) und dem Wert. Jedes Schlüssel-Wert-Paar wird in einer Zeile der StringList im Format Key = Value gespeichert.
procedure Demo(const FileName: string = ''); var SL: TStringList; i: Integer; begin SL:= TStringList.Create; try //Adding a Key-Value pair can be done this way SL.Values['FirstName']:= 'John'; //Key is 'FirstName', Value is 'John' SL.Values['LastName']:= 'Doe'; //Key is 'LastName', Value is 'Doe' //or this way SL.Add('City=Berlin'); //Key ist 'City', Value is 'Berlin' //you can get the key of a given Index IF SL.Names[0] = 'FirstName' THEN begin //and change the key at an index SL.Names[0]:= '1stName'; //Key is now "1stName", Value remains "John" end; //you can get the value of a key s:= SL.Values['City']; //s now is set to 'Berlin' //and overwrite a value SL.Values['City']:= 'New York'; //if desired, it can be saved to an file IF (FileName <> '') THEN begin SL.SaveToFile(FileName); end; finally SL.Free; end; end;
In diesem Beispiel hat die Stringliste den folgenden Inhalt, bevor sie zerstört wird:
1stName=John LastName=Doe City=New York
Hinweis zur Leistung
Unter der Haube TStringList führt die Schlüsselsuche durch, indem alle Elemente direkt durchlaufen werden, innerhalb jedes Elements nach einem Trennzeichen gesucht wird und der Namensanteil mit dem angegebenen Schlüssel verglichen wird. Es muss nicht gesagt werden, dass dies einen großen Einfluss auf die Leistung hat. Daher sollte dieser Mechanismus nur an unkritischen, selten wiederholten Orten verwendet werden. In Fällen, in denen es auf die Leistung ankommt, sollten Sie TDictionary<TKey,TValue> von System.Generics.Collections , die die Hashtabellensuche implementieren, oder die Schlüssel in sortierter TStringList mit Werten
https://riptutorial.com/de/home 32
speichern, die als Object -s gespeichert sind, und den binären Suchalgorithmus verwenden.
TStringList-Klasse online lesen: https://riptutorial.com/de/delphi/topic/6045/tstringlist-klasse
https://riptutorial.com/de/home 33
Kapitel 12: Verwendung von RTTI in Delphi
Einführung
Delphi stellte vor mehr als einem Jahrzehnt Runtime Type Information (RTTI) bereit. Doch auch heute sind sich viele Entwickler der Risiken und Vorteile nicht voll bewusst.
Kurz gesagt, Runtime-Typ-Informationen sind Informationen zum Datentyp eines Objekts, der zur Laufzeit in den Speicher gesetzt wird.
Mit RTTI können Sie feststellen, ob der Typ eines Objekts dem Typ einer bestimmten Klasse oder einer ihrer Nachkommen entspricht.
Bemerkungen
RTTI IN DELPHI - ERKLÄRT
Die Laufzeit-Typinformationen in Delphi - kann dies alles für Sie tun? Artikel von Brian Long bietet eine großartige Einführung in die RTTI-Funktionen von Delphi. Brian erklärt, dass die RTTI-Unterstützung in Delphi in erster Linie hinzugefügt wurde, damit die Entwurfszeitumgebung ihre Arbeit erledigen kann, dass Entwickler jedoch auch die Möglichkeit haben können, bestimmte Code-Vereinfachungen zu erreichen. Dieser Artikel bietet auch einen guten Überblick über die RTTI-Klassen sowie einige Beispiele.
Beispiele sind: Lesen und Schreiben von beliebigen Eigenschaften, allgemeine Eigenschaften ohne gemeinsamen Vorfahren, Kopieren von Eigenschaften von einer Komponente in eine andere usw.
Examples
Grundlegende Klasseninformationen
In diesem Beispiel wird ClassType , wie die Vorfahren einer Komponente mithilfe der ClassType und ClassParent Eigenschaften ClassType werden. Es verwendet eine Schaltfläche Button1: TButton und ein Listenfeld ListBox1: TListBox in einem Formular TForm1 .
Wenn der Benutzer auf die Schaltfläche klickt, werden der Name der Klasse der Schaltfläche und die Namen der übergeordneten Klassen zum Listenfeld hinzugefügt.
procedure TForm1.Button1Click(Sender: TObject) ; var ClassRef: TClass; begin ListBox1.Clear; ClassRef := Sender.ClassType; while ClassRef <> nil do begin
https://riptutorial.com/de/home 34
ListBox1.Items.Add(ClassRef.ClassName) ; ClassRef := ClassRef.ClassParent; end; end;
Das Listenfeld enthält die folgenden Zeichenfolgen, nachdem der Benutzer auf die Schaltfläche geklickt hat:
TButton•TButtonControl•TWinControl•TControl•TComponent•TPersistent•TObject•
Verwendung von RTTI in Delphi online lesen: https://riptutorial.com/de/delphi/topic/9578/verwendung-von-rtti-in-delphi
https://riptutorial.com/de/home 35
Kapitel 13: Verwendung von try außer und zum Schluss
Syntax
Try-Exception: try [Anweisungen] außer [[[[bei E: ExceptionType do-Anweisung]] [else-Anweisung] | [Anweisungen] Ende;
Try-finally: try [Anweisungen] finally [Anweisungen] end;
1.
Examples
Einfaches try..finally Beispiel, um Speicherlecks zu vermeiden
Verwenden Sie try - zum finally , um Ressourcenlecks (wie Speicher) zu vermeiden, falls während der Ausführung eine Ausnahme auftritt.
Die folgende Prozedur speichert eine Zeichenfolge in einer Datei und verhindert, dass die TStringList .
procedure SaveStringToFile(const aFilename: TFilename; const aString: string); var SL: TStringList; begin SL := TStringList.Create; // call outside the try try SL.Text := aString; SL.SaveToFile(aFilename); finally SL.Free // will be called no matter what happens above end; end;
Unabhängig davon, ob beim Speichern der Datei eine Ausnahme auftritt, wird SL freigegeben. Jede Ausnahme geht an den Anrufer.
Ausnahmesichere Rückgabe eines neuen Objekts
Wenn eine Funktion ein Objekt zurückgibt (im Gegensatz zur Verwendung eines Objekts, das vom Aufrufer übergeben wurde), ist zu beachten, dass eine Ausnahme das Objekt nicht verliert.
function MakeStrings: TStrings; begin // Create a new object before entering the try-block. Result := TStringList.Create; try // Execute code that uses the new object and prepares it for the caller. Result.Add('One');
https://riptutorial.com/de/home 36
MightThrow; except // If execution reaches this point, then an exception has occurred. We cannot // know how to handle all possible exceptions, so we merely clean up the resources // allocated by this function and then re-raise the exception so the caller can // choose what to do with it. Result.Free; raise; end; // If execution reaches this point, then no exception has occurred, so the // function will return Result normally. end;
Naive Programmierer versuchen möglicherweise, alle Ausnahmetypen abzufangen und nil aus einer solchen Funktion zurückzugeben. nil ist jedoch nur ein Spezialfall der generell unmutigen Praxis, alle Ausnahmetypen zu erfassen, ohne sie zu behandeln.
Try-endlich verschachtelt in Try-Exceptions
Ein try - finally - Block kann innerhalb eines try - mit except Blocks - verschachtelt sein.
try AcquireResources; try UseResource; finally ReleaseResource; end; except on E: EResourceUsageError do begin HandleResourceErrors; end; end;
Wenn innerhalb von UseResource eine Ausnahme auftritt, UseResource Ausführung zu ReleaseResource . Wenn die Ausnahme ein EResourceUsageError , springt die Ausführung zum Ausnahmehandler und ruft HandleResourceErrors . Ausnahmen eines anderen Typs überspringen den Ausnahmebehandler oben und blasen bis zum nächsten try - except Blockieren des Aufrufstapels.
Ausnahmen in AcquireResource oder ReleaseResource dazu, dass die Ausführung an den Ausnahmebehandler geht und den finally Block überspringt, entweder weil der entsprechende try Block noch nicht eingegeben wurde oder weil der finally Block bereits eingegeben wurde.
Try-Ausnahme verschachtelt in Try-finally
Ein try - except Block kann innerhalb eines try - finally Blocks verschachtelt sein.
AcquireResource; try UseResource1; try UseResource2;
https://riptutorial.com/de/home 37
except on E: EResourceUsageError do begin HandleResourceErrors; end; end; UseResource3; finally ReleaseResource; end;
Wenn in UseResource2 ein EResourceUsageError auftritt, UseResource2 Ausführung zum Ausnahmehandler und ruft HandleResourceError . Die Ausnahme wird als behandelt betrachtet, sodass die Ausführung weiterhin bei UseResource3 und dann bei ReleaseResource .
Wenn in UseResource2 eine Ausnahme eines anderen Typs auftritt, wird der hier angegebene Ausnahmebehandler nicht UseResource3 Ausführung springt dann über den Aufruf von UseResource3 und geht direkt zum finally Block, in dem ReleaseResource aufgerufen wird. Danach springt die Ausführung zum nächsten anwendbaren Ausnahmebehandlungsprogramm, da die Ausnahmebedingung den Aufrufstapel aufbläst.
Wenn bei einem anderen Aufruf im obigen Beispiel eine Ausnahme auftritt, werden HandleResourceErrors nicht aufgerufen. Dies liegt daran, dass keine der anderen Aufrufe innerhalb des try Blocks erfolgt, der diesem Ausnahmehandler entspricht.
Try-finally mit 2 oder mehr Objekten
Object1 := nil; Object2 := nil; try Object1 := TMyObject.Create; Object2 := TMyObject.Create; finally Object1.Free; Object2.Free; end;
Wenn Sie die Objekte nicht mit " nil außerhalb des try-finally Blocks initialisieren, wird beim try-finally Block ein AV ausgelöst, da das Objekt nicht null ist (da es nicht initialisiert wurde) und wird eine Ausnahme verursachen.
Die Free Methode prüft, ob das Objekt null ist. Wenn Sie beide Objekte mit nil initialisieren, werden Fehler vermieden, wenn Sie sie freigeben, wenn sie nicht erstellt wurden.
Verwendung von try außer und zum Schluss online lesen: https://riptutorial.com/de/delphi/topic/3055/verwendung-von-try-au-er-und-zum-schluss
https://riptutorial.com/de/home 38
Kapitel 14: Zeichenketten
Examples
String-Typen
Delphi verfügt über die folgenden Zeichenfolgentypen (in Reihenfolge der Beliebtheit):
ArtMaximale Länge
Mindestmaß Beschreibung
string 2 GB 16 BytesEine verwaltete Zeichenfolge. Ein Alias für AnsiString durch Delphi 2007 und ein Alias für UnicodeString ab Delphi 2009.
UnicodeString 2 GB 16 BytesEine verwaltete Zeichenfolge im UTF-16-Format.
AnsiString 2 GB 16 BytesEine verwaltete Zeichenfolge im vor-Unicode-ANSI-Format. Ab Delphi 2009 enthält es einen expliziten Codepage-Indikator.
UTF8String 2 GB 16 BytesEin verwalteter String im UTF-8-Format, der als AnsiString mit einer UTF-8-Codepage implementiert ist.
ShortString255 Zeichen
2 BytesEine ältere, nicht verwaltete Saite mit fester Länge und sehr wenig Aufwand
WideString 2 GB 4 BytesFür COM-Interop vorgesehen, eine verwaltete Zeichenfolge im UTF-16-Format. Entspricht dem Windows- BSTR Typ.
UnicodeString und AnsiString sind Referenzzähler und Copy-on-Write (COW). ShortString und WideString werden nicht als Referenz gezählt und haben keine COW-Semantik.
Zeichenketten
uses System.Character; var S1, S2: string; begin S1 := 'Foo'; S2 := ToLower(S1); // Convert the string to lower-case S1 := ToUpper(S2); // Convert the string to upper-case
https://riptutorial.com/de/home 39
Zeichen
2009
uses Character; var C1, C2: Char; begin C1 := 'F'; C2 := ToLower(C1); // Convert the char to lower-case C1 := ToUpper(C2); // Convert the char to upper-case
Die uses sollte System.Character wenn die Version XE2 oder höher ist.
Groß-und Kleinschreibung
uses SysUtils; var S1, S2: string; begin S1 := 'Foo'; S2 := LowerCase(S1); // S2 := 'foo'; S1 := UpperCase(S2); // S1 := 'FOO';
Zuordnung
Zuweisen von string zu verschiedenen String-Typen und wie sich die Laufzeitumgebung in Bezug auf sie verhält. Speicherzuordnung, Referenzzählung, indizierter Zugriff auf Zeichen und Compiler-Fehler, falls zutreffend beschrieben.
var SS5: string[5]; {a shortstring of 5 chars + 1 length byte, no trailing `0`} WS: Widestring; {managed pointer, with a bit of compiler support} AS: ansistring; {ansistring with the default codepage of the system} US: unicodestring; {default string type} U8: UTF8string;//same as AnsiString(65001) A1251: ansistring(1251); {ansistring with codepage 1251: Cryllic set} RB: RawbyteString; {ansistring with codepage 0: no conversion set} begin SS5:= 'test'; {S[0] = Length(SS254) = 4, S[1] = 't'...S[5] = undefined} SS5:= 'test1'; {S[0] = 5, S[5] = '1', S[6] is out of bounds} SS5:= 'test12'; {compile time error} WS:= 'test'; {WS now points to a constant unicodestring hard compiled into the data segment} US:= 'test'+IntToStr(1); {New unicode string is created with reference count = 1} WS:= US; {SysAllocateStr with datacopied to dest, US refcount = 1 !} AS:= US; {the UTF16 in US is converted to "extended" ascii taking into account the codepage in AS possibly losing data in the process} U8:= US; {safe copy of US to U8, all data is converted from UTF16 into UTF8} RB:= US; {RB = 'test1'#0 i.e. conversion into RawByteString uses system default codepage} A1251:= RB; {no conversion takes place, only reference copied. Ref count incremented }
https://riptutorial.com/de/home 40
Referenzzählung
Das Zählen von Referenzen auf Strings ist Thread-sicher. Sperren und Ausnahmebehandler werden verwendet, um den Prozess abzusichern. Betrachten Sie den folgenden Code mit Kommentaren, die angeben, wo der Compiler zur Kompilierzeit Code einfügt, um Referenzzählungen zu verwalten:
procedure PassWithNoModifier(S: string); // prologue: Increase reference count of S (if non-negative), // and enter a try-finally block begin // Create a new string to hold the contents of S and 'X'. Assign the new string to S, // thereby reducing the reference count of the string S originally pointed to and // brining the reference count of the new string to 1. // The string that S originally referred to is not modified. S := S + 'X'; end; // epilogue: Enter the `finally` section and decrease the reference count of S, which is // now the new string. That count will be zero, so the new string will be freed. procedure PassWithConst(const S: string); var TempStr: string; // prologue: Clear TempStr and enter a try-finally block. No modification of the reference // count of string referred to by S. begin // Compile-time error: S is const. S := S + 'X'; // Create a new string to hold the contents of S and 'X'. TempStr gets a reference count // of 1, and reference count of S remains unchanged. TempStr := S + 'X'; end; // epilogue: Enter the `finally` section and decrease the reference count of TempStr, // freeing TempStr because its reference count will be zero.
Wie oben gezeigt, erfordert das Einführen einer temporären lokalen Zeichenfolge zum Speichern der Änderungen an einem Parameter den gleichen Aufwand wie das direkte Durchführen von Änderungen an diesem Parameter. Das Deklarieren einer Zeichenfolge const nur das Zählen von Referenzen, wenn der Zeichenfolgenparameter wirklich schreibgeschützt ist. Um zu vermeiden, dass Implementierungsdetails außerhalb einer Funktion durchsickern, sollten Sie immer einen der Parameter const , var oder out für den String verwenden.
Kodierungen
String-Typen wie UnicodeString, AnsiString, WideString und UTF8String werden mit ihrer jeweiligen Codierung in einem Speicher gespeichert (weitere Informationen finden Sie unter String-Typen). Das Zuweisen eines Typs eines Strings in einen anderen kann zu einer Konvertierung führen. Der Typ string ist so konzipiert, dass er unabhängig von der Codierung ist. Sie sollten niemals seine interne Darstellung verwenden.
Die Klasse Sysutils.TEncoding stellt die Methode GetBytes zum Konvertieren von string in TBytes (Array von Bytes) und GetString zum Konvertieren von TBytes in string TBytes . Die Klasse Sysutils.TEncoding bietet auch viele vordefinierte Kodierungen als Klasseneigenschaften.
https://riptutorial.com/de/home 41
Eine Möglichkeit, mit Codierungen umzugehen, besteht darin, in Ihrer Anwendung nur den string Typ zu verwenden und jedes Mal, wenn Sie eine bestimmte Codierung verwenden müssen, TEncoding zu verwenden - normalerweise bei E / A-Operationen, DLL-Aufrufen usw.
procedure EncodingExample; var hello,response:string; dataout,datain:TBytes; expectedLength:integer; stringStream:TStringStream; stringList:TStringList; begin hello := 'Hello World!Привет мир!'; dataout := SysUtils.TEncoding.UTF8.GetBytes(hello); //Conversion to UTF8 datain := SomeIOFunction(dataout); //This function expects input as TBytes in UTF8 and returns output as UTF8 encoded TBytes. response := SysUtils.TEncoding.UTF8.GetString(datain); //Convertsion from UTF8 //In case you need to send text via pointer and length using specific encoding (used mostly for DLL calls) dataout := SysUtils.TEncoding.GetEncoding('ISO-8859-2').GetBytes(hello); //Conversion to ISO 8859-2 DLLCall(addr(dataout[0]),length(dataout)); //The same is for cases when you get text via pointer and length expectedLength := DLLCallToGetDataLength(); setLength(datain,expectedLength); DLLCall(addr(datain[0]),length(datain)); response := Sysutils.TEncoding.GetEncoding(1250).getString(datain); //TStringStream and TStringList can use encoding for I/O operations stringList:TStringList.create; stringList.text := hello; stringList.saveToFile('file.txt',SysUtils.TEncoding.Unicode); stringList.destroy; stringStream := TStringStream(hello,SysUtils.TEncoding.Unicode); stringStream.saveToFile('file2.txt'); stringStream.Destroy; end;
Zeichenketten online lesen: https://riptutorial.com/de/delphi/topic/3957/zeichenketten
https://riptutorial.com/de/home 42
Kapitel 15: Zeitintervallmessung
Examples
Verwenden der Windows-API GetTickCount
Die Windows-API-Funktion GetTickCount gibt die Anzahl der Millisekunden zurück, seit das System (Computer) gestartet wurde. Das einfachste Beispiel lautet:
var Start, Stop, ElapsedMilliseconds: cardinal; begin Start := GetTickCount; // do something that requires measurement Stop := GetTickCount; ElapsedMillseconds := Stop - Start; end;
Beachten Sie, dass GetTickCount 32-Bit- DWORD - DWORD sodass alle 49,7 Tage DWORD werden. Um das Wrapping zu vermeiden, können Sie entweder GetTickCount64 (verfügbar seit Windows Vista) oder spezielle Routinen zur Berechnung der Tick-Differenz verwenden:
function TickDiff(StartTick, EndTick: DWORD): DWORD; begin if EndTick >= StartTick then Result := EndTick - StartTick else Result := High(NativeUInt) - StartTick + EndTick; end; function TicksSince(Tick: DWORD): DWORD; begin Result := TickDiff(Tick, GetTickCount); end;
Auf GetTickCount diese Routinen falsche Ergebnisse, wenn das Intervall von zwei GetTickCount Aufrufen von GetTickCount die 49,7-Tage-Grenze überschreitet.
So konvertieren Sie Millisekunden in Sekunden:
var Start, Stop, ElapsedMilliseconds: cardinal; begin Start := GetTickCount; sleep(4000); // sleep for 4 seconds Stop := GetTickCount; ElapsedMillseconds := Stop - Start; ShowMessage('Total Seconds: ' +IntToStr(round(ElapsedMilliseconds/SysUtils.MSecsPerSec))); // 4 seconds end;
TStopwatch-Datensatz verwenden
https://riptutorial.com/de/home 43
Aktuelle Versionen von Delphi werden mit dem TStopwatch- Datensatz geliefert , der für die Zeitintervallmessung dient. Verwendungsbeispiel:
uses System.Diagnostics; var StopWatch: TStopwatch; ElapsedMillseconds: Int64; begin StopWatch := TStopwatch.StartNew; // do something that requires measurement ElapsedMillseconds := StopWatch.ElapsedMilliseconds; end;
Zeitintervallmessung online lesen: https://riptutorial.com/de/delphi/topic/2425/zeitintervallmessung
https://riptutorial.com/de/home 44
Credits
S. No
Kapitel Contributors
1Erste Schritte mit Embarcadero Delphi
Charlie H, Community, Dalija Prasnikar, Florian Koch, Jeroen Wiert Pluimers, René Hoffmann, RepeatUntil, Rob Kennedy, Vadim Shakun, w5m, Y.N, Zam
2
Aktualisierte TDataSet-Daten in einem Hintergrundthread abrufen
MartynA
3Andere Programme ausführen
Dalija Prasnikar
4Animationen in Firemonkey verwenden
Alexander Petrosyan
5Einen Thread ausführen, während die GUI ansprechend bleibt
Fr0sT, Jerry Dodge, Johan, kami, LU RD, Marjan Venema
6 Für LoopsFilipe Martins, Jeroen Wiert Pluimers, John Easley, René Hoffmann, Rob Kennedy, Siendor, Y.N
7 Generics Rob Kennedy, Steffen Binas, Uli Gerhardt
8Leicht entfernbare Laufzeitfehlerprüfungen erstellen
Alex T
9 Schleifen Y.N
10 Schnittstellen Florian Koch, Willo van der Merwe
11 TStringList-Klasse Charlie H, Fabricio Araujo, Fr0sT, KaiW
12Verwendung von RTTI in Delphi
Petzy, René Hoffmann
13Verwendung von try außer und zum Schluss
EMBarbosa, Fabio Gomes, Johan, MrE, Nick Hodges, Rob Kennedy, Shadow
14 ZeichenkettenAlekXL, Dalija Prasnikar, EMBarbosa, Fabricio Araujo, Johan, Radek Hladík, René Hoffmann, RepeatUntil, Rob Kennedy, Rudy Velthuis
https://riptutorial.com/de/home 45
15 Zeitintervallmessung Fr0sT, John Easley, kludg, Rob Kennedy, Victoria, Wolf
https://riptutorial.com/de/home 46