Delphi-PRAXiS
Seite 1 von 2  1 2      

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Programmieren allgemein (https://www.delphipraxis.net/40-programmieren-allgemein/)
-   -   Objekte in verschiedenen Formularen zentral initialisieren (https://www.delphipraxis.net/216522-objekte-verschiedenen-formularen-zentral-initialisieren.html)

Smiley 11. Jan 2025 17:11

Objekte in verschiedenen Formularen zentral initialisieren
 
Ich möchte in verschiedenen Formularen alle Objekte eines Typs auf feste Werte setzen, in einer zentralen procedure.
Dafür verwende ich folgende procedure in meiner Unit uInitForm.pas.
Code:
procedure InitFormControls(lfrm: TForm);
var
  i: Integer;
  component: TComponent;
begin
  with lfrm do
  begin
    for i := 0 to ComponentCount - 1 do
    begin
      component := Components[i];

      // Prüfen, ob die Komponente eine Font-Eigenschaft besitzt
      if component is TControl then
      begin
        // Fontname setzen für Textobjekte
        TControlAccess(component).Font.Name := FontNameGlobal;
      end;

      if component is TGraphicControl then
      begin
        // Fontname setzen für Grafikelemente
        TControlAccess(component).Font.Name := FontNameGlobal;
      end;

      if component is TPanel then
      // Prüfen, ob die Komponente ein TPanel ist
      begin
        (component as TPanel).Color := clFormBackground;
        (component as TPanel).BevelOuter := bvNone;
        (component as TPanel).Caption := '';
        (component as TPanel).Color := clFormBackground;
        (component as TPanel).ParentColor := True;
        (component as TPanel).ParentFont := True;
        (component as TPanel).ShowCaption := False;
      end;
    end;
  end;
end;
Dies rufe ich z.B. aus form1 auf mit:

Code:
procedure TfrmForm1.FormShow(Sender: TObject);
begin
  InitFormControls(Sender as TForm);
end;
Dies funktioniert soweit ich es getestet habe.

Jetzt möchte ich aber alle Forms aus eine zentralen Form FormMain aufrufen:
Dabei will ich dann die Form übergeben die initialisiert werden soll (Form1 oder Form2 oder Form3)
wie übergebe ich hier den Sender-Parameter.
Wenn ich die jeweilige Form übergebe, bekomme ich eine Memory Exception.
InitFormControls(Form1);

Oder geht das alles noch einfacher?

dummzeuch 11. Jan 2025 17:18

AW: Objekte in verschiedenen Formularen zentral initialisieren
 
Die Exception kommt vermutlich deshalb, weil die FormX noch nicht erzeugt wurde und deshalb die FormX-Variable keinen gültigen Wert enthält.

Vielleicht könntest Du InitFormControls einfach aus dem jeweiligen Constructor der Form aufrufen statt aus Deiner Hauptform?
Delphi-Quellcode:
constructor TForm5.Create(Owner: TComponent);
begin
  inherited;
  InitFormControls(Self);
end;
Oder aus dem OnCreate-Event der Form.

Oder Du leitest alle Forms von einer Standard-Form ab und rufst in deren Constructor InitFormControls auf, dann passiert das für alle abgeleiteten Forms automatisch.

Bernhard Geyer 11. Jan 2025 17:22

AW: Objekte in verschiedenen Formularen zentral initialisieren
 
1, Sorge dafür das alle Formulare eine eigene Basisklasse haben.
Also statt TForm dann TMyForm.

2, Definiere in der TMyForm eine Methode InitFormControls
Dort wird dann dein Code ausgeführt ohne with (Halte ich wie viele andere als ein zu vermeidendes Sprachkonstrukt) und übergabeparameter
Also dann

Delphi-Quellcode:
procedure TMyForm.InitFormControls;
begin
  for var i := 0 to ComponentCount - 1 do
  begin
Sehe das dummzeuch auch schon was geschrieben habe.
Das wäre mein nächsteer Punkt gewesen :-)

Smiley 11. Jan 2025 19:15

AW: Objekte in verschiedenen Formularen zentral initialisieren
 
Danke für die Vorschläge.
Das Ausführen der gleichen Zeilen in jeder Form wollte ich ja gerade vermeiden um Änderungen nur an einer Stelle zu machen.
Ist das Ändern der Komponenten im Create-Ereignis denn möglich, wenn die Komponenten noch gar nicht erzeugt wurden?
Dass die Fehlermeldung möglicherweise auf ein nicht erstelltes Element zurückzuführen ist vermute ich auch, habe es aber extra in eine procedure gelegt die nach dem Erstellen der Forms aufgerufen wird.
Ich wollte etwas Hilfe zum übergeben der Form in der InitFormControls Procedure, warum ich frmForm1 nicht übergeben kann, wenn doch der Übergabeparameter ein TForm Typ ist.

DaCoda 11. Jan 2025 23:25

AW: Objekte in verschiedenen Formularen zentral initialisieren
 
Liste der Anhänge anzeigen (Anzahl: 1)
Du kannst es ja eventuell so machen wie ich im beigefügten Bild zeige.

Uwe Raabe 11. Jan 2025 23:29

AW: Objekte in verschiedenen Formularen zentral initialisieren
 
Bei VCL wird aber das als erstes erzeugte Formular zum MainForm...

DaCoda 11. Jan 2025 23:39

AW: Objekte in verschiedenen Formularen zentral initialisieren
 
Liste der Anhänge anzeigen (Anzahl: 1)
Uwe, danke für den Hinweis. Dann kann er aber die zusätzlichen Formulare aus der automatischen Initialisierung rüber schieben nach "Verfügbare Formulare und dann im OnCreate oder OnShow selber erzeugen,
danach hätte er dann ja das nötige Erreicht.

Delphi.Narium 12. Jan 2025 00:27

AW: Objekte in verschiedenen Formularen zentral initialisieren
 
Hatte gerade mal ein bisserl "Langeweile" und da viel mir ein, dass es doch die Methode Loaded gibt, die erst nach dem Erstellen aller automatisch zu erstellenden Formulare eines Programmes aufgerufen wird.

Da ich das nicht so mal eben implementieren kann, hab' ich mal 'ne KI befragt:
Zitat:

Zitat von Frage
Wenn ich in einem Delphiprogramm nach der Initialisierung aller Formulare für die darauf befindlichen TControl-Nachfahren eine einheitliche Konfiguration an einer zentralen Stelle durchführen möchte, wie ließe sich dies realisieren? Die Konfigurationsdaten sollten ggfls. aus einer Ini-Datei (oder auf ähnlichem Weg) ausgelesen werden. Im Idealfall wäre dies alles an einer zentralen Stelle, eventuell einer eigenen Unit, zu realisieren.

Zitat:

Zitat von Antwort
Um eine einheitliche Konfiguration für alle TControl-Nachfahren in allen Formularen eines Delphi-Programms nach der Initialisierung durchzuführen, können Sie die folgende Lösung implementieren:

Erstellen Sie eine separate Unit für die zentrale Konfiguration, z.B. "ConfigManager.pas".
In dieser Unit definieren Sie eine Klasse TConfigManager mit Methoden zum Laden der Konfiguration aus einer INI-Datei und zum Anwenden der Konfiguration auf die Formulare.
Verwenden Sie die Loaded-Methode des Hauptformulars, um die Konfiguration nach der Initialisierung aller Formulare anzuwenden.

Hier ist ein Beispiel für die Implementierung:

Delphi-Quellcode:
unit ConfigManager;

interface

uses
  System.SysUtils, System.Classes, Vcl.Forms, Vcl.Controls, System.IniFiles;

type
  TConfigManager = class
  private
    FIniFile: TIniFile;
  public
    constructor Create;
    destructor Destroy; override;
    procedure LoadConfig;
    procedure ApplyConfigToForms;
  end;

implementation

constructor TConfigManager.Create;
begin
  inherited;
  FIniFile := TIniFile.Create(ChangeFileExt(Application.ExeName, '.INI'));
end;

destructor TConfigManager.Destroy;
begin
  FIniFile.Free;
  inherited;
end;

procedure TConfigManager.LoadConfig;
begin
  // Laden Sie hier Ihre Konfigurationsdaten aus der INI-Datei
  // Beispiel:
  // FButtonColor := FIniFile.ReadInteger('Controls', 'ButtonColor', clBtnFace);
end;

procedure TConfigManager.ApplyConfigToForms;
var
  i, j: Integer;
  Form: TForm;
  Control: TControl;
begin
  for i := 0 to Screen.FormCount - 1 do
  begin
    Form := Screen.Forms[i];
    for j := 0 to Form.ComponentCount - 1 do
    begin
      if Form.Components[j] is TControl then
      begin
        Control := TControl(Form.Components[j]);
        // Wenden Sie hier Ihre Konfiguration auf die Controls an
        // Beispiel:
        // if Control is TButton then
        //   TButton(Control).Color := FButtonColor;
      end;
    end;
  end;
end;

end.
Zitat:

Im Hauptformular überschreiben Sie die Loaded-Methode, um die Konfiguration anzuwenden:
Delphi-Quellcode:
unit MainForm;

interface

uses
  Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics,
  Vcl.Controls, Vcl.Forms, Vcl.Dialogs, ConfigManager;

type
  TFormMain = class(TForm)
  private
    FConfigManager: TConfigManager;
  protected
    procedure Loaded; override;
  public
    constructor Create(AOwner: TComponent); override;
    destructor Destroy; override;
  end;

var
  FormMain: TFormMain;

implementation

{$R *.dfm}

constructor TFormMain.Create(AOwner: TComponent);
begin
  inherited;
  FConfigManager := TConfigManager.Create;
end;

destructor TFormMain.Destroy;
begin
  FConfigManager.Free;
  inherited;
end;

procedure TFormMain.Loaded;
begin
  inherited;
  FConfigManager.LoadConfig;
  FConfigManager.ApplyConfigToForms;
end;

end.
Zitat:

Diese Lösung bietet folgende Vorteile:

Zentralisierte Konfiguration in einer separaten Unit.
Automatische Anwendung der Konfiguration auf alle Formulare und Controls nach der Initialisierung.
Einfache Erweiterbarkeit für verschiedene Control-Typen und Konfigurationsoptionen.

Stellen Sie sicher, dass Sie die ConfigManager-Unit in den Uses-Klauseln aller Formulare einbinden, die konfiguriert werden sollen. Diese Methode ermöglicht eine flexible und wartbare Lösung für die einheitliche Konfiguration aller Formulare und Controls in Ihrem Delphi-Programm.
Nur so als Idee. Etwas vom Prinzip sehr Ähnliches, bei dem die Konfigurationsdaten aus der Registry gelesen werden und beim Programmende zurückgeschrieben werden, hab' ich vor Jahren mal für Delphi 7 implementiert. Das Grundprinzip des KI-Beispiels kommt dem sehr nahe, so dass ich davon ausgehe, dass Du das Beispiel übernehmen kannst und eine Anpassung an Deine Anforderungen möglich sein sollte.

Kas Ob. 12. Jan 2025 08:44

AW: Objekte in verschiedenen Formularen zentral initialisieren
 
Well, if all your forms are already dpr created, meaning they are in the available forms in project options, then something like this should work
Delphi-Quellcode:
procedure TMainForm.FormCreate(Sender: TObject);
begin
  // These also could be adjusted and moved to initialization section
  FAlreadyActivated := False;

  // in case OnActivate is used in the project then it should be stored and restored later*
  Application.OnActivate := OnApplicationActivate;
end;

procedure TMainForm.OnApplicationActivate(Sender: TObject);
var
  C: Integer;
begin
  // ExitProc assigned in TApplication.Run meanning it could be used as indicator for done creating forms
  // can help in case Application.Activate wrongly (missused by) being called from a form constructor
  if not Assigned(ExitProc) then
    Exit;

  if not FAlreadyActivated then
  begin
    C := Application.ComponentCount;
    while C > 0 do
    begin
      Dec(C);
      if Application.Components[C] is TForm then
        // InitFormControls(Application.Components[C]);

    end;
  end;
  FAlreadyActivated := True;
  // here is later* ,( to restore original or more useful OnActivate)
end;
For runtime created forms and to minimize and centralize the code, use DDetours to hook TForm.Create then execute the original code followed by your InitFormControls after checking that the TForm is one of yours, if you would use DDetours then you don't any any code like the above.

https://github.com/MahdiSafsafi/DDetours

Smiley 12. Jan 2025 14:26

AW: Objekte in verschiedenen Formularen zentral initialisieren
 
Ich habe berücksichtigt, dass die Formulare erst erstellt werden müssen.
Dazu habe ich im frmMain.Activate die Formulare erst created, dann einem Tab des OfficePagers von TMS zugewiesen und danach erst das Show und LoadKunden mit dem InitFormControls ausgeführt.
Bei Ausführung von LoadKunden bzw. InitFormControls(frmKunden As TForm) tritt dann die Exception:
"Zugriffsverletzung an Adresse xxxx in Modul 'Programm.exe' (Offset(xxx)). Lesen von Adresse 00000010."
Code:
procedure TfrmMain.FormActivate(Sender: TObject);
var
  frmTabKunden: TfrmKunden;
  frmTabInteressent: TfrmInteressent;
  frmTabPartner: TfrmPartner;
  frmTabAngestellte: TfrmAngestellte;
  frmTabKassen: TfrmKassen;
  PagerHeight: Integer;
begin
  // --------------------------------------------
  // Größe und Positionierung des Hauptformulars
  PagerHeight := 540; // Höhe des inneren Tabs bis vor das Grid

  frmMain.Top := 20; // Main Formular Position Top und Left
  frmMain.Left := 20;

  frmMain.Height := 1000; // Größe des Main Formulars
  frmMain.Width := 1830;
  // --------------------------------------------

  OfficePager.Height := PagerHeight;

  // --------------------------------------------
  // Formulare in das OfficePager Element einbinden

  // --------------------------------------------
  // TabKunden
  frmTabKunden := TfrmKunden.Create(TabKunden);
  frmTabKunden.Parent := TabKunden;
  frmTabKunden.Align := alClient;
  frmTabKunden.BorderStyle := bsNone;
  frmTabKunden.Show;
  LoadKunden;
  // --------------------------------------------
.
.
.
  OfficePager.ActivePage := TabKunden;
end;

 
procedure TfrmMain.LoadKunden;
var
  s:string;
  i, sp: Integer;
begin
  s:='-----------Kunden----------';
  DebugOut(s);

  InitFormControls(frmKunden); // Hier tritt das Problem auf
  frmKunden.InitFormKunden;
.
.
.
end;


Alle Zeitangaben in WEZ +1. Es ist jetzt 10:45 Uhr.
Seite 1 von 2  1 2      

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