Autor |
Beitrag |
Gausi
      
Beiträge: 8548
Erhaltene Danke: 477
Windows 7, Windows 10
D7 PE, Delphi XE3 Prof, Delphi 10.3 CE
|
Verfasst: Di 16.01.07 21:28
Ich hab hier ein kleines Problem mit ner Komponente, die ich von TPanel abgeleitet habe. Diese hat ein OnPaint Event, sowie ein Canvas. Sinn ist der, dass ich selbst das Panel gestalten kann, ohne Paintboxen o.ä. über das Panel legen zu müssen. Das sieht bei mir dann so aus:
Delphi-Quelltext 1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18: 19: 20: 21: 22: 23: 24: 25: 26: 27:
| unit NempPanel; type TNempPanel = class(TPanel) private FOnPaint: TNotifyEvent; FOwnerDraw: Boolean; protected procedure Paint; override; public property Canvas; published property OnPaint: TNotifyEvent read FOnPaint write FOnPaint; property OwnerDraw: Boolean read FOwnerDraw write FOwnerDraw; end;
implementation
procedure TNempPanel.Paint; begin if FOwnerDraw AND Assigned(FOnPaint) then FOnPaint(Self) else inherited paint; end; end. | Dasselbe habe ich auch mit ner Groupbox gemacht.
Ich habe nun in meiner Anwendung so ein Panel, und darauf mehrere solcher Groupboxen mit OnPaint-Event. Wenn nun auf einer dieser Groupbox etwas passiert (es wird ein Button verschoben, bzw. er ändert von alleine seine Position), wird da sinnigerweise das OnPaint-Event ausgelöst. Das ist gewollt. Leider verursacht das scheinbar eine OnPaint-Kaskade. D.h. OnPaint des Parent-Panels wird mehrfach aufgerufen (immer 13mal), und das OnPaint-Event der "Nachbar-Groupboxen" wird ebenfalls aufgerufen. In welcher Reihenfolge das genau passiert, habe ich noch nicht herausgefunden. Ich vermute, dass das OnPaint der Box ein Paint des Parents aufruft, was dann seinerseits die Childs neumalt, die dann wieder das Parent neu zeichnen (das würde dann mit den 13 in etwa hinkommen).
Das möchte ich gerne verhindern, da ich dadurch unter anderem ein Flackern bekomme. Gibts da nen Trick, oder muss ich anders an die Sache rangehen?
Ziel ist es, dass ich eine Komponente habe, die entweder von Windows gezeichnet wird (Standardaussehen), aber auch selbst gezeichnet werden kann (z.B. Hintergrundbild).
_________________ We are, we were and will not be.
|
|
alias5000
      
Beiträge: 2145
WinXP Prof SP2, Ubuntu 9.04
C/C++(Code::Blocks, VS.NET),A51(Keil),Object Pascal(D2005PE, Turbo Delphi Explorer) C# (VS 2008 Express)
|
Verfasst: Di 16.01.07 23:00
Schau mal ob dir dieser Code was bringt: www.delphi-forum.de/...68639&highlight=
powered by 100th topic
Gruß alias5000
_________________ Programmers never die, they just GOSUB without RETURN
|
|
Gausi 
      
Beiträge: 8548
Erhaltene Danke: 477
Windows 7, Windows 10
D7 PE, Delphi XE3 Prof, Delphi 10.3 CE
|
Verfasst: Mi 17.01.07 00:49
So auf die Schnelle: Damit lässt sich was in der Richtung anfangen. Ein erster Versuch bewirkte ein endloses gegenseitiges Repaint, ein zweiter eine Verringerung von 13 auf 9 Repaints, dafür einige Darstellungsfehler. Ich werde aber da weiterprobieren.
Das ganze hängt auch vom Darstellungsmodus ab - bei Einstellung "klassisch" gibts deutlich weniger Repaints (nur noch 2) als beim "XP-Stil". Hängt vermutlich damit zusammen, dass im XP-Stil die Groupbox transparent ist...
Ich vermute allerdings, dass es da noch was anderes gibt. Oder ist es normal, dass ein Paint-Event an das Parent-Control durchgereicht wird? Und falls ja, wie kann man das unterbinden?
Nach unten ist das ja sinnvoll (also das ein Control beim Paint auch seine Childs neumalt). Aber nach oben? Ich hoffe mal, dass mir morgen früh jemand sagt, was ich bei der Komponente falsch gemacht habe  .
_________________ We are, we were and will not be.
|
|
Martok
      
Beiträge: 3661
Erhaltene Danke: 604
Win 8.1, Win 10 x64
Pascal: Lazarus Snapshot, Delphi 7,2007; PHP, JS: WebStorm
|
Verfasst: Mi 17.01.07 00:59
Ich werf jetzt vor dem Schlafengehen nochmal was in den Raum:
WM_ERASEBACKGROUND. Könnte das was damit zu tun haben, dass die immer mit einem WM_PAINT auftritt, und dann 'irgendwen' neu zeichnen will?
Die könnte man dann mit msg.Result := 1 abwürgen, vielleicht hilft das?
_________________ "The phoenix's price isn't inevitable. It's not part of some deep balance built into the universe. It's just the parts of the game where you haven't figured out yet how to cheat."
|
|
Gausi 
      
Beiträge: 8548
Erhaltene Danke: 477
Windows 7, Windows 10
D7 PE, Delphi XE3 Prof, Delphi 10.3 CE
|
Verfasst: Mi 17.01.07 12:06
Ohja, das hilft. Ein
Delphi-Quelltext 1: 2: 3: 4: 5: 6: 7: 8: 9: 10:
| private procedure WMEraseBkGnd(var Message: TWMEraseBkGnd); message WM_ERASEBKGND; procedure TNempGroupBox.WMEraseBkGnd(var Message: TWMEraseBkGnd); begin if FOwnerDraw AND Assigned(FOnPaint) then Message.Result := 1 else inherited; end; | verringert das Neuzeichnen auf ein vernünftiges Maß (noch 5, aber das liegt wohl daran, dass ich beim Panel das noch nicht eingebaut habe, und auch noch vier kleine Panels auf dem Panel mit den ganzen Groupboxen liegen) und das flackern ist weg. Ich hatte gehofft, dass ein Message.Result irgendwo was bringen würde, aber wo ich das genau (und was genau) einbauen sollte, war mir unklar. Manchmal braucht man nur das richtige Stichwort. Danke! 
_________________ We are, we were and will not be.
|
|
Martok
      
Beiträge: 3661
Erhaltene Danke: 604
Win 8.1, Win 10 x64
Pascal: Lazarus Snapshot, Delphi 7,2007; PHP, JS: WebStorm
|
Verfasst: Mi 17.01.07 20:58
*Juhuu, richtig geraten  *
Schön, dass ich helfen konnte 
_________________ "The phoenix's price isn't inevitable. It's not part of some deep balance built into the universe. It's just the parts of the game where you haven't figured out yet how to cheat."
|
|
delfiphan
      
Beiträge: 2684
Erhaltene Danke: 32
|
Verfasst: Sa 20.01.07 05:24
Wie gesagt ist dein Flackern auf das Zeichnen des Hintergrundes zurückzuführen... Das ist weder mit Double-Buffered zu beseitigen, noch hat das mit mehrmaligem Aufrufen von OnPaint zu tun. Die WM_ERASEBKGND-Methode verhindert natürlich immer dieses Flackern, denn die Ursache für das Flackern wird beseitigt. Je nach dem führt das aber zu unerwünschten Nebeneffekten - grundlos wird der Hintergrund ja nicht gelöscht. Wenn bei deinem Fall nirgends der Hintergrund durchschimmert (weil du die ganze Fläche bemalst) funktioniert die Methode. Wenn du jedoch die Standard-Skins von Windows zulassen willst, würde ich das nicht unbedingt empfehlen, da das vorherie Zeichnen des Hintergrundes eventuell notwendig ist.
Übrigens: Bei den 13 Paints handelt es sich kaum um die selben Bereiche, die gezeichnet werden sollen, oder? Sondern es handelt sich bestimmt um verschiedene Bereiche um die Child-Components herum? So ineffizient ist Windows wahrscheinlich nicht  ganz im Gegenteil: Wenn sich die Bereiche tatsächlich nicht überschneiden, dann finde ich das recht clever von Windows.
|
|
Gausi 
      
Beiträge: 8548
Erhaltene Danke: 477
Windows 7, Windows 10
D7 PE, Delphi XE3 Prof, Delphi 10.3 CE
|
Verfasst: Sa 20.01.07 11:19
delfiphan hat folgendes geschrieben: | Je nach dem führt das aber zu unerwünschten Nebeneffekten - grundlos wird der Hintergrund ja nicht gelöscht. Wenn bei deinem Fall nirgends der Hintergrund durchschimmert (weil du die ganze Fläche bemalst) funktioniert die Methode. Wenn du jedoch die Standard-Skins von Windows zulassen willst, würde ich das nicht unbedingt empfehlen, da das vorherie Zeichnen des Hintergrundes eventuell notwendig ist. |
Die Komponenten sind von TPanel bzw. TGroupbox abgeleitet. Unter XP sind diese transparent (wenn man ein Manifest auf der Form hat, siehe Anhang). Wenn die Groupbox/Panel neugezeichnet wird, ist somit ein Repaint des Hintergrundes nötig. In meinem Fall übermale ich die Box aber komplett, und es schimmert nichts durch. Daher auch das if... else inherited. Ohne dem ist die Konstruktion z.B. zur Entwurfszeit sehr unübersichtlich
delfiphan hat folgendes geschrieben: | Übrigens: Bei den 13 Paints handelt es sich kaum um die selben Bereiche, die gezeichnet werden sollen, oder? Sondern es handelt sich bestimmt um verschiedene Bereiche um die Child-Components herum? So ineffizient ist Windows wahrscheinlich nicht ganz im Gegenteil: Wenn sich die Bereiche tatsächlich nicht überschneiden, dann finde ich das recht clever von Windows. |
Das kann sein. Ich habe nur die Paint-Ereignisse einer Groupbox gezählt, und die ging in 13er-Schritten hoch.
Einloggen, um Attachments anzusehen!
_________________ We are, we were and will not be.
|
|
jaenicke
      
Beiträge: 19315
Erhaltene Danke: 1747
W11 x64 (Chrome, Edge)
Delphi 11 Pro, Oxygene, C# (VS 2022), JS/HTML, Java (NB), PHP, Lazarus
|
Verfasst: Sa 20.01.07 12:20
Bei WM_ERASEBACKGROUND habe ich allerdings im Moment das Problem, dass, wenn ich es abfange, es Grafikfehler gibt. Bei mir habe ich eine VirtualTreeView und eigene Scrollbars rechts und unten, die natürlich mitgehen. Dabei "fühlt sich jetzt das Programm träge an", wenn man es resized, weil es Schlieren zieht, wenn man es vergrößert. Der Repaint kommt nicht häufig genug. Ich muss noch herausfinden, woran das liegt.
Aber was ich damit sagen will: Wenn du auch die Komponente mit dem Formular resizen willst, dann solltest du ausprobieren was passiert, wenn du es ein wenig schneller vergrößerst oder so (vielleicht liegts bei mir aber auch nur an der VirtualTreeView).
Bzw. wenn ich mir den Namen der GroupBox so ansehe, dann ist das mit dem Testen ja ohnehin kein Problem  .
|
|
|