![]() |
(Formular-)Handling größerer Projekte
Hallo DP-Gemeinde,
wenn eine App nur ein oder wenige Fenster hat, ist die Sache ja ziemlich einfach. Da kann man mit der Delphi-Automatik (Erzeugen der Formulare in der dpr) gut leben. Etwas anders sieht es aus, wenn die App größer wird. Hier gibt es wohl sehr unterschiedliche Ansichten, Meinungen und Praktiken. Das bringt mich zu der Frage, ob denn meine Praxis was taugt und ob man vielleicht daran noch etwas optimieren könnte? Hintergrund meiner Frage ist auch: Ich bin gelerter Elektriker der sich das Programmieren im Selbststudium angeeignet hat. Ich hab also noch keine Uni von innen gesehen. Manchmal stelle ich mir darum die Frage, ob das was ich mache auch Stand der Technik ist. Weil, für Optimierungen muss man(n) bekanntlich immer ein offenes Ohr haben. Generell erzeuge ich in der dpr nur die Datenmodule und das Hauptformular:
Delphi-Quellcode:
Die INC sieht so aus:
{------------------------------------------------------------------------------}
{-} {$I Project1.inc} {--------------------------------------------------------} {------------------------------------------------------------------------------} program Project1; uses {$IFDEF DEBUG} FastMM4, {$ENDIF} Vcl.Forms, uMainForm in 'uMainForm.pas' {FrmMainForm}, uClientForm1 in 'uClientForm1.pas' {FrmClient1}, uClientForm2 in 'uClientForm2.pas' {FrmClient2}, uMainData in 'uMainData.pas' {MainData: TDataModule}; {$R *.res} begin {$IFDEF DEBUG} ReportMemoryLeaksOnShutdown := True; {$ENDIF} Application.Initialize; Application.MainFormOnTaskbar := True; Application.CreateForm(TMainData, MainData); Application.CreateForm(TFrmMainForm, FrmMainForm); Application.Run; end.
Delphi-Quellcode:
Das Hauptformular:
{------ Standard-Compiler-Optionen --------------------------------------------}
{-----} {$A+,B+,C+,E-,F-,G+,H+,J+,K-,M-,N+,O+,P+,S-,T-,U-,V+,W-,X+,Y-,Z1} {----} {$IFDEF DEBUG} {$DEFINE TEST} {$ENDIF} {- Range-Check und Debug-Info wahlweise beim Testen ein/aus -------------------} {$IFDEF TEST} {$DEFINE UseRangeCheck} {$DEFINE CreateDebugInfo} {$ENDIF} {$IFDEF UseRangeCheck} {$Q+,R+} {$ELSE} {$Q-,R-} {$ENDIF UseRangeCheck} {$IFDEF CreateDebugInfo} {$D+ L+} {$OPTIMIZATION ON} {$DEBUGINFO ON} {$LOCALSYMBOLS ON} {$REFERENCEINFO ON} {$DEFINITIONINFO ON} {$ASSERTIONS ON} {$ELSE} {$OPTIMIZATION ON} {$DEBUGINFO OFF} {$LOCALSYMBOLS OFF} {$REFERENCEINFO OFF} {$DEFINITIONINFO OFF} {$ASSERTIONS OFF} {$ENDIF CreateDebugInfo}
Delphi-Quellcode:
Normales Formular (ist bei etwa 8 Formularen ein MDI-Formular)
{------------------------------------------------------------------------------}
{-} {$I Project1.inc} {--------------------------------------------------------} {------------------------------------------------------------------------------} unit uMainForm; interface uses Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics, Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.StdCtrls; type TFrmMainForm = class(TForm) Button1: TButton; Button2: TButton; procedure Button1Click(Sender: TObject); procedure Button2Click(Sender: TObject); private { Private-Deklarationen } public { Public-Deklarationen } end; var FrmMainForm: TFrmMainForm; implementation {$R *.dfm} uses uClientForm1, uClientForm2; procedure TFrmMainForm.Button1Click(Sender: TObject); begin FrmClient1_Show; end; procedure TFrmMainForm.Button2Click(Sender: TObject); begin case FrmClient2_ShowModal of mrOk : ShowMessage('OK'); mrCancel : ShowMessage('Cancel'); end; end; end.
Delphi-Quellcode:
Modale Formulare:
{------------------------------------------------------------------------------}
{-} {$I Project1.inc} {--------------------------------------------------------} {------------------------------------------------------------------------------} unit uClientForm1; interface uses Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics, Vcl.Controls, Vcl.Forms, Vcl.Dialogs; type TFrmClient1 = class(TForm) procedure FormCreate(Sender: TObject); procedure FormClose(Sender: TObject; var Action: TCloseAction); private { Private-Deklarationen } public { Public-Deklarationen } end; var FrmClient1: TFrmClient1 = nil; FrmClient1Active: boolean = false; procedure FrmClient1_Show; implementation {$R *.dfm} procedure FrmClient1_Show; begin if not FrmClient1Active then FrmClient1 := TFrmClient1.Create(Application); FrmClient1.Show; end; procedure TFrmClient1.FormClose(Sender: TObject; var Action: TCloseAction); begin Action := caFree; FrmClient1Active := false; end; procedure TFrmClient1.FormCreate(Sender: TObject); begin FrmClient1Active := true; end; end.
Delphi-Quellcode:
Detail-Fragen:
{------------------------------------------------------------------------------}
{-} {$I Project1.inc} {--------------------------------------------------------} {------------------------------------------------------------------------------} unit uClientForm2; interface uses Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics, Vcl.Controls, Vcl.Forms, Vcl.Dialogs; type TFrmClient2 = class(TForm) private { Private-Deklarationen } public { Public-Deklarationen } end; function FrmClient2_ShowModal: integer; implementation {$R *.dfm} function FrmClient2_ShowModal: integer; begin with TFrmClient2.Create(Application) do try Result := ShowModal; finally Release; end; end; end. 1) Gibt es hinsichtlich einer optimalen Exe-Größe bei der Include-Datei noch Optimierungsmöglichkeiten? 2) Bei den normalen und MDI-Fenstern würde ich gerne die globalen Variablen lokal machen, also im implemantation-Teil, damit der versehentliche Zugriff aus dem Hauptformular bzw. auch anderen Formularen (wenn ein untergeordnetes Formular wiederum ein weiteres Formular aufruft) ausgeschlossen ist. Ich habe es testweise mal probiert und keine Nebenwirkungen festgestellt. oder 3) Macht es Sinn, die Boolean-Variablen weg zu lassen, und stattdessen auf NIL zu prüfen? Wenn ja, wie geht das zuverlässig? Stichwort mögliche Exceptions beim Anzeigen oder Schließen. Ich möchte in jedem Fall wie bisher den Speicher beim Beenden eines Formulares wieder frei geben denn es befinden sich insgesamt über 100 Formulare im Projekt. Vielen Dank schon mal für eure Anregungen. |
AW: (Formular-)Handling größerer Projekte
Zu 1) weiß ich nicht. :stupid:
zu 2) Man sollte Variablen immer so lokal wie möglich deklarieren. Von daher ist das eine gute Idee zu 3) Du kannst mit Assigned(FrmClient1) prüfen, ob die Variable zugewiesen ist. Dabei solltest Du aber beim Freigeben des Formulars FreeAndNil(FrmClient1) nutzen. Dann funktioniert das zuverlässig und Du kannst die Boolschen Variablen einsparen. Der Fachbegriff für das, was Du da machst, ist übrigens "lazy initialization" Die Vorgehensweise beim Modalen Formular kannst Du so machen. Ich würde es etwas anders schreiben (lokale Variable für die Instanz deklarieren und das with weglassen), das ist hier im Endeffekt egal. |
AW: (Formular-)Handling größerer Projekte
Zitat:
|
AW: (Formular-)Handling größerer Projekte
Zitat:
Delphi-Quellcode:
Also kein FreeAndNil, denn das Free wird ja automatisch durch das Action:=caFree ausgelöst.
procedure TFrmClient1.FormClose(Sender: TObject; var Action: TCloseAction);
begin Action := caFree; FrmClient1:=nil; end; |
AW: (Formular-)Handling größerer Projekte
Hi mm1256
Wenn du das Formular aus sich selber heraus schliessen willst, dann musst du es mit Release freigeben. Machst du das mit Free oder FreeAndNil, wird das Formular freigegeben, und die Ausführung kehrt zur auslösenden Prozedur zurück - die nicht mehr da ist, da das Formular freigegeben wurde. Und desshalb knallts. Wenn du hingegen von einem MDI-Fenster ein MDI-Childd freigibst (zB.), passiert das nicht. Gruss Delbor |
AW: (Formular-)Handling größerer Projekte
Danke für den Tipp. Hab es soeben mal ausprobiert. Funktioniert.
Ein Verständnisproblem (ich möchte ja auch verstehen was ich mache und nicht nur irgend einen Code abschreiben :-D) hab ich noch: Wenn ich im "OnClose" mit FrmClient1:=nil die Variable FrmClient1 auf NIL setze, wie schafft es Delphi (der Speichermanager oder was auch immer...) dann hinterher die Variable FrmClient1 trotzdem noch frei zu geben? |
AW: (Formular-)Handling größerer Projekte
@Delbor Sorry, hat sich jetzt überschnitten.
Die Verwendung von Release bei modalen Fenstern ist mir klar. Aber bei normalen und MDI-Fenstern verstehe ich das noch nicht ganz. So wie es aussieht scheint aber die von "bcvs" vorgeschlagene Variante zu funktionieren. |
AW: (Formular-)Handling größerer Projekte
Du erzeugst ja eine Instanz der Klasse TForm. Diese Diese Instanz gibt sich selbst frei, wenn im das Action im Onclose auf caFree steht. Dazu braucht es eigentlich überhapt keine Instanzvariable (in deinem Fall FrmClient1).
Dein FrmClient zeigt nur zusätzlich noch auf die Instanz, kann aber auch nil sein oder theoretisch sonst irgendwohin zeigen. |
AW: (Formular-)Handling größerer Projekte
Jetzt ist mir das auch klar. "zusätzlich" war das magische Wort. Vielen Dank nochmals für deine Hilfe!
|
AW: (Formular-)Handling größerer Projekte
Hi zusammen
Zitat:
![]() Nach wie vor: ein Formular, das sich selbst freigeben soll, muss mit Release geschlossen werden. Ein Beispiel:
Delphi-Quellcode:
Hier klickt der Anwender auf den Button, der sich in Form1 befindet. Dadurch wird OnClose aufgerufen; die Programmausführung arbeitet also FormOnClose ab und tut das, was der Parameter
var TForm1;
implementation; ... ... procedure TForm1.ButtonClose.Onclick(Sender:TObject); begin Form1.Close; end; procedure TForm1.FormClose(Sender: TObject; var Action: TCloseAction); begin Action:= caFree; //Action := caHide; end; ![]() Nachdem FormClose abgearbeitet ist, kehrt die Programmmausführung zur aufrufenden Prozedur zurück - aber Scheibenkleister, die ist ja gar nicht mehr da!! Also was macht Delphi! Eine AV auslösen? Mit ![]() ![]() Ein modales Formular kann, muss aber nicht mit Release freigegeben werden, da sich die Behandlungsroutine nicht im modalen Formular befindet. Gruss Delbor |
Alle Zeitangaben in WEZ +1. Es ist jetzt 21:53 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