Delphi-PRAXiS

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Win32/Win64 API (native code) (https://www.delphipraxis.net/17-win32-win64-api-native-code/)
-   -   Delphi Maus auf Form: andere Priorität beim Repaint? (https://www.delphipraxis.net/82703-maus-auf-form-andere-prioritaet-beim-repaint.html)

alzaimar 18. Dez 2006 15:32


Maus auf Form: andere Priorität beim Repaint?
 
Hi Leute,

Kleines Problem: Ein Grid (DevExpress, aber egal) muss immer mal wieder neu gezeichnet werden. Die Methode hierfür heisst: 'Invalidate'. Das klappt auch.... Fast.

Wenn nämlich:
- die Maus nicht auf dem Grid liegt, scheint es etwas seltener zu klappten (Vielleicht subjektiv)
- eine andere Form OnTop ist und die Maus auf dieser Form 'liegt', wird das Grid gar nicht gezeichnet. Die OnTop-Form hat den Fokus. Offensichtlich wird das darunter/danebenliegende Fenster (das mit dem Grid) stiefmütterlich behandelt und zeichnet sich nicht. Gut. Bewege ich die Maus über das Grid-Fenster (Fokus ist immer noch auf dem OnTop-Fenster), zeichnet sich das Grid, allerdings mehr schlecht als recht.

Frage:
1. Kann mir Jemand dieses Verhalten erklären (Focused etc.).
2. Ist es wirklich so, das die unten liegenden Fenster irgendwie stiefmütterlich behandelt werden?
3. Kann man dafür sorgen, das so ein Fenster trotzdem immer gezeichnet wird? Außer den Fokus setzen...

Danke für Hinweise, Aufklärung und Nachhilfe!

:dp:

Olli 19. Dez 2006 01:40

Re: Maus auf Form: andere Priorität beim Repaint?
 
Zitat:

Zitat von alzaimar
2. Ist es wirklich so, das die unten liegenden Fenster irgendwie stiefmütterlich behandelt werden?

Ja, denn ansonsten wäre es verschwendete Rechenzeit. Allerdings sollte eine Komponente immer nur die sichtbaren Teile neu zeichnen. Das alles läßt sich anhand der Win32-API ermitteln. Hast du den Source zu diesem Grid?

alzaimar 19. Dez 2006 06:42

Re: Maus auf Form: andere Priorität beim Repaint?
 
Hi Olli,

Klar irgendwie, das hintenliegende Fenster eine niedrigere Priorität haben. Den Sourcecode habe ich, aber das sind ca. 200.000 Zeilen. Mittlerweile habe ich aber den Fehler gefunden:

Wenn das Grid neu gezeichnet werden muss, setze ich ein globales Flag. Im Application.OnIdle frage ich das Flag ab und "zeichne" das Grid ggf. neu. Das Zeichnen des Grids bewerkstellige ich mit 'Invalidate'. Danach hat das Grid aber keine Chance mehr, der Aufforderung nachzukommen, das OnIdle bis zum nächsten Event nicht mehr aufgerufen wird... :wall:

Danke für die Aufklärung.

marabu 19. Dez 2006 09:15

Re: Maus auf Form: andere Priorität beim Repaint?
 
Hallo alzaimar,

Zitat:

Zitat von alzaimar
... Das Zeichnen des Grids bewerkstellige ich mit 'Invalidate'. ...

nicht wirklich - mit Invalidate() setzt du ja auch nur einen internen marker, effektiv gezeichnet wird mit Repaint().

Freundliche Grüße

Olli 19. Dez 2006 12:17

Re: Maus auf Form: andere Priorität beim Repaint?
 
Weihnachtliche Grüße an meinen Lieblingsforen-"Vogel"!!! :-D

Zitat:

Zitat von marabu
Zitat:

Zitat von alzaimar
... Das Zeichnen des Grids bewerkstellige ich mit 'Invalidate'. ...

nicht wirklich - mit Invalidate() setzt du ja auch nur einen internen marker, effektiv gezeichnet wird mit Repaint().

Prinzipiell hast du natürlich recht, aber im Default-Handler erledigt Windows genau das nach einem Invalidate(). Ich würde also sagen, daß es stark von der Implementierung abhängt, die er einsetzt.

alzaimar 19. Dez 2006 12:28

Re: Maus auf Form: andere Priorität beim Repaint?
 
Hi Olli:
Schau:

<In irgendeinem Thread, z.B. nach Empfang einer TCP-Message>
Delphi-Quellcode:
Procedure TSomeWhere.OnTCPMessageReceived;
Begin
  PleaseUpdateGrid := True
End;

<Im Application.OnIdle>
Delphi-Quellcode:
Procedure TMainForm.ApplicationIdle (Sender : TObject; Var Done : Boolean);
Begin
  If PleaseUpdateGrid then Begin
     ViewController.UpdateGrid;
     PleaseUpdateGrid := False;
  End
End;
...

Procedure TViewController.UpdateGrid;
Begin
  ...
  MyGrid.Invalidate
  ...
End;
Das geht natürlich so nicht mehr, weil Invalidate aufgerufen wird und danach nix mehr kommt. Das Grid-Neuzeichnen wird dann erst nach dem Bewegen der Maus/Keyboard etc. initiiert.

Meine Frage richtete sich aber eher danach, wie (und ob) ich Windows 'zwingen' kann, ein nicht fokusiertes Fenster im Hintergrund auch ofters mal neu zu zeichnen...

marabu 19. Dez 2006 13:58

Re: Maus auf Form: andere Priorität beim Repaint?
 
Hallo Olli,

Zitat:

Zitat von Olli
... im Default-Handler erledigt Windows genau das nach einem Invalidate(). ...

ich untermauere meine Behauptung, dass mit Invalidate() nicht gezeichnet wird, mit dieser Code-Stelle aus der VCL:

Delphi-Quellcode:
procedure TWinControl.Repaint;
begin
  Invalidate;
  Update;
end;
Ein Repaint() gefolgt von einem Application.ProcessMessages - das muss schon sein, da sonst das auf WM_PAINT basierende UpdateWindow() nicht funktioniert - sollte den gewünschten Erfolg bringen, wenn (1) die Komponente von TWinControl abgeleitet wurde und (2) Windows keinen Einspruch erhebt.

@alzaimar: probiere es doch mal aus, wenn du Zeit hast.

Vorweihnachtliche Grüße

alzaimar 19. Dez 2006 14:11

Re: Maus auf Form: andere Priorität beim Repaint?
 
Hi marabu: Diese Developer-Express-Komponente ist schon sehr komplex:

Wenn der Anwender gerade eine Zelle bearbeitet und ich rufe ein 'Repaint' auf, dann wird die Eingabe abgebrochen (Seiteneffekt). Das geht natürlich nicht.

Also mache ich es so: Wenn die Anforderung ('PleaseUpdateGrid') gesetzt ist, ruft OnIdle zunächst 'Invalidate' auf und anschließend setzt sie den 'Done'-Parameter auf False, damit OnIdle nochmal aufgerufen wird. Frag mich nicht wieso, aber das klappt.

Ist das Flag 'PleaseUpdateGrid' nicht gesetzt, wird 'Done' auf True gesetzt und die Welt ist in Ordnung.

marabu 19. Dez 2006 14:25

Re: Maus auf Form: andere Priorität beim Repaint?
 
Hi alzaimar,

das ist aber schon das von mir erwartete Verhalten, immerhin auch so dokumentiert: Nach Invalidate() zeichnet Windows "bei Gelegenheit" alle für ungültig erklärten Rechtecke neu, auch wenn sie in der Z-Ordnung weiter hinten liegen. OnIdle() heißt ja, dass sonst nix zu tun ist. Also ist das eine passende Gelegenheit. Deine Lösung für das Problem ist theoretisch äquivalent zu meinem Vorschlag, scheint aber noch die Komplexität einer Komponente zu berücksichtigen, die ich nicht kenne.

Freundliche Grüße

@Olli: Versuchst du dich diese Woche schnell noch im burst mode ins Buch der guten Taten zu schmuggeln? Ich merke sowas ...

alzaimar 19. Dez 2006 14:30

Re: Maus auf Form: andere Priorität beim Repaint?
 
Zitat:

Zitat von marabu
...Deine Lösung für das Problem ist theoretisch äquivalent zu meinem Vorschlag, scheint aber noch die Komplexität einer Komponente zu berücksichtigen, die ich nicht kenne. ...

Das Verfahren mit der ich auf die Lösung gekommen bin, nennt sich im Fachjargon: "Extreme-Hair-Raufing".

marabu 19. Dez 2006 18:32

Re: Maus auf Form: andere Priorität beim Repaint?
 
Zitat:

Zitat von alzaimar
... Das Verfahren ... nennt sich im Fachjargon: "Extreme-Hair-Raufing".

Solche Verfahren benachteiligen Menschen mit einem dritten Knie und sind deshalb extreme unfair ...

Muetze1 19. Dez 2006 20:25

Re: Maus auf Form: andere Priorität beim Repaint?
 
Zitat:

Zitat von marabu
Ein Repaint() gefolgt von einem Application.ProcessMessages - das muss schon sein, da sonst das auf WM_PAINT basierende UpdateWindow() nicht funktioniert - sollte den gewünschten Erfolg bringen, wenn (1) die Komponente von TWinControl abgeleitet wurde und (2) Windows keinen Einspruch erhebt.

Nein, da habe ich andere Erfahrungen gemacht.

Zitat:

Zitat von MSDN
The UpdateWindow function updates the client area of the specified window by sending a WM_PAINT message to the window if the window's update region is not empty. The function sends a WM_PAINT message directly to the window procedure of the specified window, bypassing the application queue. If the update region is empty, no message is sent.

Somit ist Application.ProcessMessages hinfällig. Auch habe ich die Erfahrung gemacht, dass mit der Rückkehr von UpdateWindow() ohne Fehler das Fenster auch fertig gezeichnet wurde. Daher ist das Aufrufen von Application.ProcessMessages zu dem Zeitpunkt eh zu spät.

Wie ich das rausgefunden habe? Ich habe in meiner Anwendung eine Lupe selbst implementiert. Wenn ich Aktionen an einem grafischen Objekt gemacht habe (z.B. verschoben), so habe ich alle solche Aktionen mit Invalidate(Rect) begleitet, damit das grafische SubSystem meiner App das System und die App nicht ausbremst (bei bis zu 10.000 Objekte auch dringend nötig). Im Paint Handler wird das ClipRect des TCanvas honoriert, was die Systemlast auch immens mindert. Ok, das zu Einleitung. Ich hatte den Fehler festgestellt, dass beim verschieben der Objekte die Lupe immer ein verpätetes Bild darstellte. Dies war das Problem des Invalidate, welches in höherer Ebene gefolgt wurde von einem BitBlt() für die Lupe. Nach dem Einfügen von einem UpdateWindow(Handle) vor dem BitBlt() ist das Bild nun immer hunderprozentig korrekt und somit war sichergestellt, dass mit der Rückkehr von UpdateWindow() die Canvas schon aktuell ist. Auch auf den lahmsten Kisten läuft es, also liegt es nicht am schnellen Rechner.

marabu 20. Dez 2006 07:50

Re: Maus auf Form: andere Priorität beim Repaint?
 
Hallo Thomas,

gut dass du das klar gestellt hast, aber hier steht nicht Erfahrung gegen Erfahrung: Ich hatte lediglich nach WM_PAINT schon aufgehört zu lesen.

Freundliche Grüße


Alle Zeitangaben in WEZ +1. Es ist jetzt 11:43 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