Implementierung normaler Fenster in Delphi
Zusammenfassung In der VCL -Bibliothek von Delphi erstellt die Anwendungsobjektanwendung ein verstecktes Fenster für die Bearbeitung von Nachrichtenantworten. Es ist dieses Fenster, in dem die mit VCL entwickelten Programme etwas deformiert zu sein scheinen, z. Durch eingehende Analyse von VCL bietet dieser Artikel eine Lösung, die das Problem lösen kann, indem nur 3 Codezeilen in die Anwendungsprojektdatei geändert werden, ohne Änderungen an der ursprünglichen Programmiermethode.
Schlüsselwort VCL, normales Fenster, Normalisierung
1 Einführung
Windows -Anwendungen, die in der von Delphi bereitgestellten VCL -Klassenbibliothek geschrieben wurden, haben eine eigene Funktion, die sich offensichtlich vom Standardfenster des Windows unterscheidet. Das Systemmenü des Hauptfensters unterscheidet sich vom Systemmenü in der Taskleiste. Im Allgemeinen enthält das Systemmenü im Hauptfenster sechs Menüelemente, während das Menü Taskleistensystem nur drei Menüelemente enthält. In der tatsächlichen Verwendung haben wir festgestellt, dass Programme, die mit VCL entwickelt wurden, die folgenden Verlegenheit haben:
1) Nicht schön genug. Dies ist sicher, wenn es nicht mit den Standards übereinstimmt, erscheint es natürlich etwas deformiert.
2) Es gibt keinen Animationseffekt, wenn das Hauptfenster minimiert wird.
3) Das Fenster kann nicht mit anderen Fenstern angeordnet und fliesen nicht angeordnet werden.
4) Das Menü "Taskleistensystem" hat die höchste Priorität. In Gegenwart eines modalen Fensters kann das gesamte Programm im Gegensatz zum Design des Modalfensters immer noch minimiert werden.
Das Problem der Minimierung von Animationseffekten im Hauptfenster wurde durch die Showwinnoanimate -Funktion in Form.pas in Versionen nach Delphi 5.0 gelöst, aber die verbleibenden Probleme bestanden immer. Obwohl dies in den meisten Fällen keinen Einfluss auf die Anwendung hat, ist es in einigen Situationen, in denen professionelle Auswirkungen verfolgt werden, in der Tat inakzeptabel. Da C ++ Builder und Delphi denselben Satz von Klassenbibliotheken verwenden, existieren die oben genannten Probleme auch in Windows -Anwendungen, die mit C ++ Builder geschrieben wurden.
Ich habe dieses Problem in früheren Artikeln (in Forrest Gumps Haus) besprochen, und die Erzählung zu dieser Zeit schien im Grunde genommen ein Trick zu sein, und ich fand diese Methode zufällig. Die Aufgabe dieses Artikels besteht darin, die VCL -Klassenbibliothek zu analysieren, um das Prinzip dafür zu erläutern und dann eine Methode anzugeben, bei der nur 3 Codezeilen verwendet werden, um das Problem dieses "abnormalen Fensters" in Delphi vollständig zu lösen.
2 Prinzip
2.1 Prozess zur Erstellung von Anwendungen
Hier ist eine typische Anwendung von Delphi -Projektdatei.
Programmprojekt1 ;
Verwendung
Formen,
UNIT1 in 'Unit1.pas' {Form1};
{$ R *.res}
Beginnen
Application.initialize;
Application.createForm (tform1, Form1);
Anwendung.Run;
Ende .
Das versteckte Fenster wird vom Anwendungsobjekt erstellt. Woher kommt das Anwendungsobjekt also? Halten Sie Strg im Code -Bearbeitungsfenster von Delphi gedrückt und klicken Sie auf die Anwendung. Dies reicht nicht aus. Wir möchten wissen, wo das Anwendungsobjekt erstellt wurde, da eine Instanz der Tapplikationsklasse erfolgreich erstellt werden muss, bevor wir uns darauf verweisen können.
Denken Sie darüber nach, gibt es einen Code, der vor der Anwendung ausgeführt wird. Übrigens ist es der Code im Initialisierungscode -Segment. Nachdem Sie den VCL -Quellcode sorgfältig debuggen, können Sie wissen, dass viele Einheiten in VCL Initialisierungscodesegmenten haben. Alle Initialisierungsaktionen.
Bei der Suche im VCL -Quellcode -Verzeichnis mit dem Schlüsselwort "tapPlication.create" haben wir den Code gefunden, um das Anwendungsobjekt in der steuerung.pas -Einheit zu erstellen. Im Initialisierungscode -Segment der Controls.pas -Einheit gibt es einen Aufruf des Initcontrols -Verfahrens, und die Implementierung von InitControls lautet wie folgt:
Einheitensteuerungen ;
…
Initialisierung
...
Initcontrols;
Verfahren initcontrols;
Beginnen
...
Maus: = tmouse.create;
Bildschirm: = tscreen.create ( nil );
Anwendung: = tapPlication.create ( nil );
...
Ende ;
OK, zu diesem Zeitpunkt hat unsere Analyse den ersten Schritt abgeschlossen, da wir vor dem Initialisieren des Anwendungsobjekts eine Sache tun müssen, um das Problem von abnormalen Fenstern zu lösen. Daher ist es sehr wichtig, den Initialisierungsprozess der Anwendung zu verstehen.
2.2 Islibraryvariablen
Die Islibrary -Variable ist eine der globalen Flag -Variablen, die im System der Systeme definiert sind. Wenn der Wert der Islibrary wahr ist, bedeutet dies, dass das Programmmodul eine dynamische Linkbibliothek ist, andernfalls ein ausführbares Programm. Einige Prozesse in der VCL -Klassenbibliothek führen verschiedene Aktionen aus, die auf unterschiedlichen Werten dieser Flag -Variablen basieren. Das heißt, diese Variable spielt eine Schlüsselrolle bei der Lösung des abnormalen Fensterproblems von Delphi.
Wie bereits erwähnt, wurde ein unsichtbares Fenster erstellt, als das Anwendungsobjekt initialisiert wurde (dh das Fenster mit "Tapplikation" als Klassenname mit Tools wie Spy ++), aber es liegt auch daran, dass das Fenster unsichtbar macht, dass das Fenster macht Die mit Delphi entwickelten Programme zeigen viele Anomalien. OK, wenn wir dieses unsichtbare Fenster entfernen können (und gleichzeitig das Menü "Taskleistensystem" entfernen und durch unser Hauptfenster unseres Anwendungs -Hauptfensters ersetzen können, würden nicht alle Probleme gelöst?
Es ist einfach zu sagen, aber muss eine größere Operation erforderlich sind, um den VCL -Quellcode zu implementieren? Wäre das nicht ein bisschen vor das Pferd? Natürlich lautet die Antwort nein, sonst wäre dieser Artikel nicht verfügbar gewesen. Was ich hier sagen möchte, ist, dass wir in der nächsten Analyse sehen werden, dass die sogenannte "Art der Programmierung in einem Geist liegt", die Praxis für unbeabsichtigte Weidepflanzung in Tapplikationsdesign lässt uns tatsächlich die Lösung für dieses Problem Die Schnittstelle. Wenn Sie keine Quellcodeanalyse durchführen, müssen Sie möglicherweise im Kreis herumlaufen. Tatsächlich werden wir jedoch sehen, dass das geniale Design uns nicht mehr oder weniger richtig macht.
Öffnen Sie den Konstruktor -Erstellen der TapPlication -Klasse und wir werden eine solche Codezeile finden.
Constructor tapPlication.create (Aowner: tcomponent);
Beginnen
...
Wenn nicht Islibrary, dann erstellen Sie Handle;
...
Ende ;
Was hier gesagt wird, ist, dass, wenn das Programmmodul keine dynamische Linkbibliothek ist, CreateHandle ausführen und die von CreateHandle geleisteten Arbeiten wie folgt in der Hilfe wie folgt lautet: "Wenn es kein Anwendungsfenster gibt, erstellen Sie ein" hier "-Anwendungsprogramm Das Fenster "ist das oben erwähnte unsichtbare Fenster, bei dem es sich um den Schuldigen handelt. In der Tapplikationsklasse wird die Fhandle -Variable verwendet, um den Fenstergriff zu speichern. Dies dient dazu, verschiedene Aktionen gemäß dem Wert der Islibrary auszuführen, da in dynamischen Verbindungsbibliotheken Nachrichtenschleifen im Allgemeinen nicht erforderlich sind. Verwenden Sie jedoch Anwendungsobjekte, um dynamische Linkbibliotheken mit VCL zu entwickeln. Hier ist hier das Design. OK, wir müssen nur das Anwendungsobjekt ausstreuen, Islibrary true zuweisen, bevor es erstellt wird, und die Ausführung von CreateHandle herausfiltern und dieses nervige Fenster entfernen.
Der dem ISLIBRARY zugewiesene Code sollte offensichtlich im Initialisierungscode -Segment einer bestimmten Einheit platziert werden. Das Anwendungsobjekt wird erstellt. In der Projektdatei müssen wir das Gerät, das den Zuordnungscode enthält, wie folgt vor der Formulare -Einheit platzieren (vorausgesetzt, das Gerät heißt Unitdllexe.pas):
Programmvorlage ;
Verwendung
Unitdllexe in 'Unitdllexe.pas',
Formen,
Formmain in 'formmain.pas' {MainForm},
...
Die Code -Liste der Unitdllexe.pas lautet wie folgt:
Einheit Unitdllexe;
Schnittstelle
Durchführung
Initialisierung
Islibrary: = wahr;
// Teilen Sie das Anwendungsobjekt mit, dass es sich um eine dynamische Linkbibliothek handelt und keine versteckten Fenster erstellen muss.
Ende .
Okay, kompilieren Sie es. Fenster. Das Problem ist jedoch, dass das Fenster nicht minimiert werden kann. Was ist los? Es ist immer noch der alte Weg, folge ihm.
2.3 Main -Fenster -Minimierung
Die Minimierung gehört zu Systembefehlen, und letztendlich muss sie als API -Funktion defWindowProc bezeichnet werden, um das Fenster zu minimieren .WndProc zu handhaben:
procedure tcustomForm.wmsyscommand ( var message: twmsysCommand);
Beginnen
mit Nachricht tun
Beginnen
if (cmdtype und $ fff0 = sc_minimize) und (application.mainForm = self) dann
Application.wndproc (tmessage (meldung))
...
Ende ;
Ende ;
In application.wndProc wird die Anwendungsmethode minimieren, als Reaktion auf die minimierte Nachricht aufgerufen wird, sodass der Kern des Problems im Minimierungsprozess liegen muss.
procedure tapPlication.wndProc ( var message: tmessage);
...
Beginnen
...
mit Nachricht tun
Fall msg von
WM_SYSCOMMAND:
Fall Wparam und $ fff0 von
Sc_minimize: minimieren;
SC_RESTORE: Wiederherstellung;
anders
Standard;
...
Ende ;
Finden Sie zum Schluss TapPlication. Minimieren Sie und Sie werden alles verstehen. Der Aufruf zur DefwindowProc -Funktion hier erzeugt keinen Effekt, warum? Da wir das Anwendungsobjekt zuvor getäuscht haben, den Anruf von CreateHandle herausgefiltert haben und das Fenster nicht erstellt haben, um auf die Nachricht des Anwendungsobjekts zu antworten, beträgt der Handle -Fandle 0 und der Anruf ist natürlich erfolglos. Wenn Sie Fandle auf unser Hauptantragsfenster verweisen können, wird das Problem gelöst.
Prozedur TapPlication.Minimize;
Beginnen
...
DefWindowProc (Fhandle, Wm_Syscommand, sc_minimize, 0);
// Der Fhandle -Wert hier ist 0
...
Ende ;
3 Implementierung
Das unbeabsichtigte Design von Borlands Genies ermöglichte es uns erneut, das Problem zu lösen. Aus der vorherigen Analyse wissen wir, dass in der mit VCL entwickelten dynamischen Linkbibliothek kein verstecktes Fenster gibt, um Windows -Nachrichten zu empfangen (CreateHandle wird nicht ausgeführt). Wenn Sie das Fenster anzeigen möchten, benötigen Sie jedoch in der dynamischen Linkbibliothek ein übergeordnetes Fenster. Wie löst ich dieses Problem? Der VCL -Designer entwirft die Fandle -Variable, die unsichtbare Fenstergriffe als beschreibbar hält, sodass wir Fhandle einfach einen Wert zuweisen können, um ein übergeordnetes Fenster für das untergeordnete Fenster anzugeben, das angezeigt werden muss. In einem dynamischen Link-Bibliotheks-Plug-In zum Anzeigen eines Formulars übergeben wir beispielsweise das Handwerk des Anwendungsobjekts über eine Funktion der dynamischen Linkbibliothek in der ausführbaren Hauptmoduldatei und weisen Sie es der Anwendung zu.HANDLE der Dynamik zu Linkbibliothek in der ausführbaren Datei der Hauptmodul und zuweisen Sie sie der Anwendung.
Prozedur setApplicationHandle (MainAppwnd: hwnd)
Beginnen
Application.Handle: = mainAppwnd;
Ende ;
OK, da Aplication.Handle eigentlich nur ein Fenstergriff ist, das intern verwendet wird, um auf Nachrichten zu antworten, und das unsichtbare Fenster, das erstellt werden sollte Es genug, um einfach den Griff des ursprünglich unnötigen Fensters zu verbergen? Wo finde ich ein solches Fenster? Das Hauptfenster der Anwendung ist die beste Wahl, daher ist der folgende Code verfügbar.
Programmvorlage ;
Verwendung
Unitdllexe in 'Unitdllexe.pas',
Formen,
Formmain in 'formmain.pas' {MainForm};
{$ R *.res}
Beginnen
Application.initialize;
Application.createForm (tFormmain, Formmain);
Application.Handle: = formain.handle;
Anwendung.Run;
Ende .
Alle Probleme wurden also gelöst. Sie müssen keine Änderungen am VCL -Quellcode vornehmen und keine Änderungen am ursprünglichen Programm vornehmen. Von drei Codezeilen, die Ihr Anwendungsfenster wie jedes Standardfenster für das Standardfenster normal sind.
1) Die Taskleiste und die Fenstertitelleiste haben konsistente Systemmenüs.
2) Es gibt einen Animationseffekt, wenn das Hauptfenster minimiert wird.
3) Das Fenster kann mit anderen Fenstern normal angeordnet und gefliest werden.
4) Wenn es ein modales Fenster gibt, kann es nicht im übergeordneten Fenster betrieben werden.
Der obige Implementierungscode wird in allen Versionen von Delphi verwendet.