Überlappende TCustomControl-Objekte werden beim Erstellen / Wiederherstellen des Formulars nicht ordnungsgemäß angeordnet

8

Ich habe Probleme, ein TCustomControl in Delphi 2007 mit Transparenz zu arbeiten. Ich habe das Problem derzeit auf den folgenden Code reduziert. Das Problem besteht darin, dass beim Erstellen des Formulars die Steuerelemente in der umgekehrten Reihenfolge gezeichnet werden, in der sie dem Formular hinzugefügt werden. Wenn die Größe des Formulars geändert wird, werden sie in der richtigen Reihenfolge angezeigt. Was mache ich falsch? Ausschließen von 3rd-Party-Lösungen gibt es einen geeigneteren Weg zu folgen?

Hier ist mein Beispielprojekt, das das Problem in Delphi 2007 demonstriert.

%Vor%     
c0pp3rt0p 01.09.2017, 18:38
quelle

1 Antwort

4

Was ist falsch ist Ihre Erwartung der Reihenfolge der Malerei Ihrer Kontrollen. Die Reihenfolge der Steuerelemente, die WM_PAINT -Nachrichten empfangen, ist tatsächlich in der genau umgekehrten Reihenfolge dokumentiert. Das oberste Steuerelement empfängt die Nachricht zuerst. Mehr zur Dokumentation später, da WS_EX_TRANSPARENT gestylte Geschwister uns in undokumentiertem Gebiet hinterlassen. Wie Sie bereits bemerkt haben, haben Sie einen Fall, in dem die Reihenfolge der Steuerelemente, die WM_PAINT -Nachrichten empfangen, nicht deterministisch ist - wenn sich die Größe des Fensters ändert, ändert sich die Reihenfolge.

Ich habe ein bisschen von Ihrem Reproduktionsfall modifiziert, um zu sehen, was passiert. Die Modifikationen sind die Einbeziehung von zwei Panels und eine Debug-Ausgabe, wenn sie WM_PAINT erhalten.

%Vor%


Welche erzeugt diese Form:

Wie von der Reihenfolge der Erstellung bestimmt, ist die Z-Reihenfolge von unten nach oben

  1. GreenBox,
  2. Panel1,
  3. Panel2,
  4. YellowBox.

Die Debugausgabe für die Nachrichten WM_PAINT lautet wie folgt:

%Vor%

Es gibt zwei Dinge, die in dieser Reihenfolge zu beachten sind.

Zuerst erhält Panel2 die Farbmeldung vor Panel1, obwohl Panel2 in der z-Reihenfolge höher ist.

Wie kommt es, dass wir Panel2 als Ganzes sehen, aber wir sehen nur einen Teil von Panel1, obwohl es später gemalt wird? Hier kommen Update-Regionen ins Spiel. Die WS_CLIPSIBLINGS Style-Flags in den Steuerelementen teilen dem Betriebssystem diesen Teil mit von einem Steuerelement, das von einem Geschwister höher in der Z-Reihenfolge besetzt ist, wird nicht gemalt werden.

  

Fügt untergeordnete Fenster relativ zueinander ein; das heißt, wenn ein bestimmter   Das untergeordnete Fenster empfängt eine WM_PAINT Nachricht, die WS_CLIPSIBLINGS   Stil schneidet alle anderen überlappenden untergeordneten Fenster aus der Region von   das untergeordnete Fenster, das aktualisiert werden soll.

Lassen Sie uns ein bisschen mehr in den WM_PAINT -Handler von Panel1 schauen und sehen, wie die Aktualisierungsregion des Betriebssystems aussieht.

%Vor%


Der BeginPaint klammert die Update-Region mit der Systemaktualisierungsregion, die Sie dann mit GetRandomRgn abrufen können. Ich habe den ausgeschnittenen Aktualisierungsbereich auf der rechten Seite des Formulars abgelegt. Beachten Sie die Form1 Referenzen oder fehlende Fehlerprüfungen, wir sind nur Debuggen. Wie auch immer, dies erzeugt die folgende Form:

Also, was auch immer Sie im Clientbereich von Panel1 zeichnen, es wird in die schwarze Form geschnitten, daher kann es nicht visuell vor Panel2 erscheinen.

Zweite , denken Sie daran, dass die grüne Box zuerst erstellt wird, dann die Panels und dann die gelbe letzte. Warum also sind die zwei transparenten Bedienelemente nach den beiden Panels lackiert?

Denken Sie zunächst daran, dass die Steuerelemente von oben nach unten bemalt sind. Wie kann es nun möglich sein, dass ein transparentes Steuerelement auf etwas gezeichnet wird, das danach gezeichnet wird? Offensichtlich ist es nicht möglich. Also muss sich der gesamte Malalgorithmus ändern. Es gibt keine Dokumentation dazu und die beste Erklärung, die ich gefunden habe, stammt von einem Blogeintrag von Raymond Chen:

  

... Der erweiterte Stil WS_EX_TRANSPARENT erweitert das Bild   Algorithmus wie folgt: Wenn ein WS_EX_TRANSPARENT Fenster sein muss   gemalt, und es hat keine WS_EX_TRANSPARENT windows Geschwister (die   gehören zu demselben Prozess), die auch gemalt werden müssen, dann die   Der Fenstermanager wird zuerst die nicht WS_EX_TRANSPARENT windows malen.

Die Reihenfolge von oben nach unten macht es schwierig, wenn Sie über transparente Steuerelemente verfügen. Dann gibt es den Fall von überlappenden transparenten Kontrollen - die transparenter ist als die andere? Akzeptieren Sie einfach die Tatsache, dass überlappende transparente Steuerelemente unbestimmtes Verhalten erzeugen.

Wenn Sie die Systemaktualisierungsbereiche der transparenten Kästchen im obigen Testfall untersuchen, werden Sie beide als exakte Quadrate finden.


Verschieben wir die Panels zwischen die Boxen.

%Vor%


Die am weitesten rechts stehende schwarze Form ist die Systemaktualisierungsregion für die GreenBox. Schließlich kann das System Clipping auf ein transparentes Steuerelement anwenden. Ich denke, es würde genügen, zu dem Schluss zu kommen, dass der Malalgorithmus nicht perfekt ist, wenn Sie eine Reihe transparenter Bedienelemente haben.

Wie versprochen, die Dokumentation für die WM_PAINT Auftrag. Ein Grund, warum ich dies bis zuletzt beibehalten habe ist, dass es eine mögliche Lösung beinhaltet (natürlich haben wir bereits eine Lösung gefunden, streuen einige nicht transparente Steuerelemente zwischen Ihre transparenten Steuerelemente):

  

...Wenn ein Fenster in der Elternkette zusammengesetzt ist (ein Fenster mit   WX_EX_COMPOSITED), Geschwisterfenster erhalten WM_PAINT Nachrichten in der   umgekehrte Reihenfolge ihrer Position in der Z-Reihenfolge. Angesichts dieser, das Fenster   am höchsten in der Z-Reihenfolge (oben) erhält seine WM_PAINT -Nachricht   zuletzt und umgekehrt. Wenn ein Fenster in der Elternkette nicht vorhanden ist   Zusammengesetzte, gleichgeordnete Fenster empfangen WM_PAINT Nachrichten in Z-Reihenfolge.

So wenig wie ich getestet habe, scheint die Einstellung von WS_EX_COMPOSITED auf dem Elternformular zu funktionieren. Aber ich weiß nicht, ob es in Ihrem Fall anwendbar ist.

    
Sertac Akyuz 05.09.2017, 02:12
quelle

Tags und Links