Delphi-PRAXiS

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   GUI-Design mit VCL / FireMonkey / Common Controls (https://www.delphipraxis.net/18-gui-design-mit-vcl-firemonkey-common-controls/)
-   -   Komponenten initialisieren (https://www.delphipraxis.net/171518-komponenten-initialisieren.html)

blablab 10. Nov 2012 10:23

Komponenten initialisieren
 
Hallo!

Manchmal ist es doch so, dass man beim Programmstart bestimmte Eigenschaften von Komponenten initialisiert. Diese Eigenschaften rufen aber Methoden auf, die beim Programmstart noch nicht ausgeführt werden dürfen.

Also ich hab gerade zum Beispiel eine Scrollbar. Ich möchte beim Programmende die alte ScrollBar.Position speichern und beim Programmstart wiederherstellen. Dabei wird aber ScrollBar.OnChange() ausgelöst und dadurch krieg ich dann beim Start einen Fehler, weil OnChange() auf Variablen zugreift, die zu dem Zeitpunkt noch nicht initialisiert sind.

Wie macht man das am geschicktesten?

Ich kann jetzt eine globale Variable "Startup: Boolean" benutzen, die nur beim Programmstart True ist. Und dann muss ich in jede Methode, die solch ein Problem hat "if not Startup then begin [...] end" schreiben.

Gibt es da vielleicht eine schönere Lösung?

Grüße
blablab

Sir Rufo 10. Nov 2012 10:41

AW: Komponenten initialisieren
 
Wann musst du denn spätestens die Scrollbar-Eigenschaft gesetzt haben?

Wenn die Form angezeigt wird - also macht man das im OnShow Event ;)

Uwe Raabe 10. Nov 2012 11:08

AW: Komponenten initialisieren
 
Zitat:

Zitat von Sir Rufo (Beitrag 1190582)
Wann musst du denn spätestens die Scrollbar-Eigenschaft gesetzt haben?

Wenn die Form angezeigt wird - also macht man das im OnShow Event ;)

Das wird aber bei jedem Show ausgeführt und man muss dort womöglich auch auf das erste Mal abprüfen.

Perlsau 10. Nov 2012 12:08

AW: Komponenten initialisieren
 
Zitat:

Zitat von blablab (Beitrag 1190581)
... Ich möchte beim Programmende die alte ScrollBar.Position speichern und beim Programmstart wiederherstellen. ... Wie macht man das am geschicktesten?

Meine Initialisierungen finden gewöhnlich im Hauptformular unter OnActivate statt (OnShow verwende ich nur selten). Bei Sub-Forms lese ich aus der zugehörigen Ini, der Registry oder einer Datenbank die entsprechenden Werte aus, wenn die Form angezeigt wird, ebenfalls in OnActivate. Beim Schließen der Sub-Forms kannst du entweder gleich im CloseQuery- oder im OnClose-Ereignis der jeweiligen Form deine Daten zurückschreiben, oder erst beim Programm-Ende im OnClose- oder im CloseQuery-Ereignis der Mainform. So speichere und lade ich z.B. komplexe benutzerseitige VirtualTreeView-Einstellungen ...

Sir Rufo 10. Nov 2012 12:20

AW: Komponenten initialisieren
 
Hmmm,
Delphi-Quellcode:
OnActivate
wird ja wesentlich häufiger als
Delphi-Quellcode:
OnShow
gefeuert

Perlsau 10. Nov 2012 12:28

AW: Komponenten initialisieren
 
Zitat:

Zitat von Sir Rufo (Beitrag 1190591)
Hmmm,
Delphi-Quellcode:
OnActivate
wird ja wesentlich häufiger als
Delphi-Quellcode:
OnShow
gefeuert

Generell? Bei jedem Programm? Und wenn schon ... Man kann doch dafür sorgen, daß OnActivate nur einmal am Start ausgeführt wird: In OnCreate wird das Flag StartModus auf True gesetzt, am Ende von OnActivate auf False. Am Beginn von OnActivate heißt es dann:
Delphi-Quellcode:
if not StartModus then exit;
Manche Initialisierungen machten in OnShow Probleme, weil zu diesem Zeitpunkt noch nicht alle Units verfügbar sind, wie mir scheint. Daher mache ich seit Jahren alles in OnActivate. Siehst du darin ein Problem?

Sir Rufo 10. Nov 2012 12:35

AW: Komponenten initialisieren
 
Es gibt dann ein Problem, wenn die Form nicht aktiviert wird. Ist allerdings wohl mehr theoretisch, denn um das zu bewerkstelligen, muss man die Create-Parameter der Form entsprechend anpassen :)

BTW Bei OnShow sind alle Units da, aber die Form u.U. noch nicht sichtbar und das macht teilweise Probleme

Perlsau 10. Nov 2012 12:41

AW: Komponenten initialisieren
 
Zitat:

Zitat von Sir Rufo (Beitrag 1190595)
Es gibt dann ein Problem, wenn die Form nicht aktiviert wird. Ist allerdings wohl mehr theoretisch, denn um das zu bewerkstelligen, muss man die Create-Parameter der Form entsprechend anpassen :)
BTW Bei OnShow sind alle Units da, aber die Form u.U. noch nicht sichtbar und das macht teilweise Probleme

Dann lieg ich wohl doch nicht so falsch mit meiner Gewohnheit, notwendige Initialisierungen in FormActivate zu belassen ...

Ich kann's jetzt gerade nicht ausprobieren, weil auf meinem Entwicklungsrechner gerade ein Virenscan läuft, den ich nicht unterbrechen möchte – aber soweit ich mich erinnere, lassen sich auch Datenbank-Komponenten im Datenmodul nicht fehlerlos zum OnCreate-Zeitpunkt initialisieren.

himitsu 10. Nov 2012 13:14

AW: Komponenten initialisieren
 
OnCreate (alt), OnCreate (neu), OnShow und OnActivte...



OnCreate (OldCreateOrder) wurde direkt im TForm.Constructor ausgelöst, also kurz nachdem die Form erstellt und die DFM geladen wurde

OnCreate (NewCreateOrder) wird im TFormAfterConstruction ausgelöst, also nachdem alles erstellt wurde
(eigentlich sollte man hier alles initialisieren, außer es gibt wirklich Probleme)

OnShow wird kurz vor dem Anzeigen ausgeführt, aber unmittelbar vor dem ersten OnActivate, wenn die Form mit Visible=True erstellt/geladen wurde

OnActivte wird jedesmal ausgeführt, wenn die Form den Eingabefokus bekommt und wenn die Form schon sichtbar ist. Es kann unter Umständen stören, wenn sich wärend des Arbeitens (Form bekommt Fokus) und auch wärend des Ladens (kurz danach, aber optisch dazugehörend) sich die Form nochmals verändert.

OnTimer, der im OnCreate aktiviert und beim ersten Aufruf wieder deaktiviert wird: entweder "kurz" nach dem OnActivate und auch, wenn die Form nicht sichtbar ist, aber nachdem definitiv alles geladen wurde (außer jemand pfuscht mit Application.ProcessMessages rum)

Uwe Raabe 10. Nov 2012 14:43

AW: Komponenten initialisieren
 
Mit folgendem Ansatz kann man ziemlich sicher sein, daß das Form sichtbar ist und der Init-Code nur einmal aufgerufen wird.

Delphi-Quellcode:
const
  WM_INITIALIZE = WM_USER + 1;

type
  TForm177 = class(TForm)
    procedure FormCreate(Sender: TObject);
  protected
    procedure WMInitialize(var Message: TMessage); message WM_INITIALIZE;
  public
  end;

...

procedure TForm177.FormCreate(Sender: TObject);
begin
  ...
  PostMessage(Handle, WM_INITIALIZE, 0, 0)
  ...
end;

procedure TForm177.WMInitialize(var Message: TMessage);
begin
  inherited;
  { hier Initialisierungscode }
end;

himitsu 10. Nov 2012 15:32

AW: Komponenten initialisieren
 
"ziemlich":

Es kommt fast auf's Selbe raus, wie mit einem Timer ... pfuscht jemand mit Application.ProcessMessages rum, war's das.
(und glaub mir, das kommt häufiger vor, als man denkt ... EurekaLog, DevExpress usw.)

Sir Rufo 10. Nov 2012 15:34

AW: Komponenten initialisieren
 
@uwe Manchmal frage ich mich warum solche Dinge in der VCL nicht von Haus aus drin sind. An zuviel Code kann es nicht liegen, wohl eher daran, dass dort einigen Entwickler in der Schule Singen und Klatschen wichtiger war :roll:

Uwe Raabe 10. Nov 2012 20:40

AW: Komponenten initialisieren
 
Zitat:

Zitat von Sir Rufo (Beitrag 1190620)
@uwe Manchmal frage ich mich warum solche Dinge in der VCL nicht von Haus aus drin sind. An zuviel Code kann es nicht liegen, wohl eher daran, dass dort einigen Entwickler in der Schule Singen und Klatschen wichtiger war :roll:

Gut möglich :lol:

himitsu 10. Nov 2012 21:38

AW: Komponenten initialisieren
 
Die Frage ist eher, warum sich nich alle Komponenten ordentlich initialisieren, dann wären Umwege nicht nötig. :zwinker:

Perlsau 10. Nov 2012 22:44

AW: Komponenten initialisieren
 
Zitat:

Zitat von himitsu (Beitrag 1190606)
OnCreate (NewCreateOrder) wird im TFormAfterConstruction ausgelöst, also nachdem alles erstellt wurde
(eigentlich sollte man hier alles initialisieren, außer es gibt wirklich Probleme)

Wenn ich innerhalb von OnCreate eine Procedure im Datenmodul aufrufe, löst das eine Zugriffsverletzung aus. Deshalb hatte ich wohl alles in OnActivate gemacht.

Zitat:

Zitat von himitsu (Beitrag 1190606)
OnShow wird kurz vor dem Anzeigen ausgeführt, aber unmittelbar vor dem ersten OnActivate, wenn die Form mit Visible=True erstellt/geladen wurde

Nun habe ich den Aufruf der Verbindungs-Funktionen in OnShow verlagert – und es tut! Vorteil: Der schleppende Aufbau der Form (enthält DBGrid, das beim Programmstart so sortiert wird, wie es beim letzten Programmende war) ist nicht mehr sichtbar. Danke, Himitsu.

Zitat:

Zitat von himitsu (Beitrag 1190606)
OnActivte wird jedesmal ausgeführt, wenn die Form den Eingabefokus bekommt und wenn die Form schon sichtbar ist. Es kann unter Umständen stören, wenn sich wärend des Arbeitens (Form bekommt Fokus) und auch wärend des Ladens (kurz danach, aber optisch dazugehörend) sich die Form nochmals verändert.

Da hast du allerdings recht, weshalb ich ja auch ein Flag verwendete, das dafür sorgte, daß OnActivate nur einmal aufgerufen wird. Jetzt kann ich mir das sparen :-D

Jetzt muß ich mir nur noch einen Splash-Screen einbauen, um die 3 Sekunden bis zur Anzeige zu überbrücken ...

himitsu 10. Nov 2012 22:54

AW: Komponenten initialisieren
 
Das Datenmodul wird aber auch vor der Form erstellt und nicht danach?

Perlsau 10. Nov 2012 23:00

AW: Komponenten initialisieren
 
Zitat:

Zitat von himitsu (Beitrag 1190669)
Das Datenmodul wird aber auch vor der Form erstellt und nicht danach?

Nein, im Projekt-Quellcode wird das Datenmodul erst nach der Form erstellt. Erstelle ich das Datenmodul vor der Mainform, kann ich auf das Datenmodul aus dem OnCreate der Mainform heraus zugreifen. Der Projekt-Quellcode war mir völlig aus dem Sinn. Danke.

Übrigens: Ich habe eben festgestellt, das OnActivate nicht bei jedem Fokus-Erhalt aufgerufen wird. Tatsächlich konnte ich es nicht bewerkstelligen, daß ein ShowMessage in OnActivate angezeigt wird außer beim Programmstart. Soweit ich mich erinnere, wird OnActivate außer beim Programmstart nur nach der Rückkehr aus einem nicht modal angezeigten Programmfenster ausgelöst ... Wenn ich lediglich mit Alt-Tab den Fokus auf ein anderes Programm lege und wieder zurück zum Projekt-Programm, passiert gar nichts ...

Uwe Raabe 11. Nov 2012 14:12

AW: Komponenten initialisieren
 
[QUOTE=Perlsau;1190670]
Zitat:

Zitat von himitsu (Beitrag 1190669)
Übrigens: Ich habe eben festgestellt, das OnActivate nicht bei jedem Fokus-Erhalt aufgerufen wird. Tatsächlich konnte ich es nicht bewerkstelligen, daß ein ShowMessage in OnActivate angezeigt wird außer beim Programmstart. Soweit ich mich erinnere, wird OnActivate außer beim Programmstart nur nach der Rückkehr aus einem nicht modal angezeigten Programmfenster ausgelöst ... Wenn ich lediglich mit Alt-Tab den Fokus auf ein anderes Programm lege und wieder zurück zum Projekt-Programm, passiert gar nichts ...

Das OnActivate sollte vollständig OnActivateFormInsideApplication heißen. Es triggert nicht, wenn lediglich die Applikation wieder den Focus erhält. Dafür gibt es TApplication.OnActivate.


Alle Zeitangaben in WEZ +1. Es ist jetzt 15:58 Uhr.

Powered by vBulletin® Copyright ©2000 - 2024, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024 by Thomas Breitkreuz