![]() |
Welche Windows-Events zum Zeichnen eines Buttons
Folgendes Problem:
Ich habe eine abgeleitete TButton-Klasse, bei der ich die Caption und noch anderes selbst zeichne. Der Button selbst wird weiterhin von Windows erstellt. Gezeichnet wird das ganze über
Delphi-Quellcode:
Bei XP kommt es manchmal vor, das AdditionalPaint nicht durchlaufen wird und der Button dann leer ist. Das ganze tritt zufällig auf und meistens, wenn ich aus einer anderen Maske wiederkomme. Fährt man mit der Maus über den leeren Button, wird das Zeichnen wieder erzwungen.
procedure TMyButton.WndProc(var Message: TMessage);
begin inherited WndProc(Message); if Message.Msg in [WM_PAINT,WM_ACTIVATE,BM_SETSTATE,WM_ENABLE,WM_NCPAINT] then begin AdditionalPaint; end; end; Meine Frage: Welche Windows-Ereignisse gibt es noch, auf die ich das Zeichnen anwerfen muss? |
Re: Welche Windows-Events zum Zeichnen eines Buttons
![]() |
Re: Welche Windows-Events zum Zeichnen eines Buttons
InvalidateRect erzeugt doch auch nur eine WM_PAINT ( + evtl. WM_ERASEBKGND) ...
Ich vermute, dass manche (Windowsbehandlungs-)Funktionen den Button direkt über DrawFrameControl neu Zeichnen und das Windows-Messageprinzip umgehen. Ich habe nämlich genau das gleiche Problem. Ein Beispiel: Wenn man in einer nicht (Manifest-) XP-Anwendung die Maustaste auf dem Button gedrückt hält, so wird dieser neu gezeichnet, aber ich erhalte nie eine Message darüber. Evtl. hilft dir ein Funktionshook weiter, ich habe an diesem Punkt keine Lust mehr gehabt weiter zu suchen. Weiterhelfen konnte mir damals auch niemand, da dies doch wirklich tief ins Eingemachte geht. Ich hänge hier mal meine alte WNDProc an, die größtenteils funktioniert. Zur Erklärung: Während die Maustasten gedrückt werden, erzeuge ich ein Overlay-Fenster, welches das Neuzeichnen des Buttons durch die Original-Wndproc verdeckt. Es gibt zwar Funktionen um das Neuzeichenen von Fenster vorübergehend zu unterdrücken, aber von diesen kann ich nur abraten, da sie negative Nebeneffekte besitzen. Besonders wenn man in Fremdanwendungen "rumwurschtelt" sollte man sich so transparent und unauffällig benehmen wie es nur möglich ist.
Delphi-Quellcode:
Dazu noch der besagte Funktionshook hat mir recht passable Ergebnisse gebracht. Ist allerdings größtenteils ungetestet. Es gibt einfach zuviele Anwendungen und Fälle.
// result= true = originalwndproc wird direkt aufgerufen
function TPulseButton.buttonWndProc( const handle: dWord; const Msg: cardinal; const wParam, lParam: dWord; var rueckgabe: dWord): Boolean; begin result:= false; if MovingControlWndProc( handle, Msg, wParam, lParam) then exit; case Msg of WM_PAINT{, WM_NCPAINT}: begin if wParam= 0 then Paint else result:= true; end; WM_TIMER: begin if WParam = 999 then NextPulse else if WParam = 996 then begin if not isAltDown then begin killTimer(handle, 996); InvalidateRect(handle, NIL, false); end; end else if WParam = 998 then checkMouseOver else if WParam = 995 then begin killTimer(handle, 995); InvalidateRect(handle, NIL, false); end else result:= true; result:= true; end; WM_SIZE, WM_WINDOWPOSCHANGED, WM_MOVE: begin Rueckgabe := CallWindowProc( origWndProc, handle, Msg, wParam, lParam); InvalidateRect(handle, NIL, false); end; WM_LBUTTONDOWN: begin if not LButtonDown then begin LButtonDown:= true; activate; createOverlayWindow; Rueckgabe := CallWindowProc( origWndProc, handle, Msg, wParam, lParam); destroyOverlayWindow; InvalidateRect(handle, NIL, false); end; end; WM_LBUTTONUP, WM_LBUTTONDBLCLK: begin if LButtonDown then begin LButtonDown:= false; createOverlayWindow; Rueckgabe := CallWindowProc( origWndProc, handle, Msg, wParam, lParam); destroyOverlayWindow; InvalidateRect(handle, NIL, false); end; end; WM_ENABLE, WM_RBUTTONDBLCLK, WM_SHOWWINDOW, WM_NCACTIVATE, WM_CAPTURECHANGED, WM_KILLFOCUS, WM_SETFOCUS, BM_SETSTATE, BM_SETSTYLE, WM_SETTEXT: begin createOverlayWindow; Rueckgabe := CallWindowProc( origWndProc, handle, Msg, wParam, lParam); destroyOverlayWindow; InvalidateRect(handle, NIL, true); Paint; InvalidateRect(handle, NIL, false); end; WM_NCHITTEST: begin Rueckgabe := HTCLIENT; InvalidateRect(handle, NIL, false); end; WM_MOUSEMOVE: begin Rueckgabe := CallWindowProc( origWndProc, handle, Msg, wParam, lParam); InvalidateRect(handle, NIL, false); killTimer(handle, 998); setTimer(handle, 998, 100, NIL); end; WM_ACTIVATEPULSING: Pulsing:= boolean( wParam); WM_NCDESTROY: begin Rueckgabe := CallWindowProc( origWndProc, handle, Msg, wParam, lParam); deInitControl( handle); end; else result:= true; end; end; |
Re: Welche Windows-Events zum Zeichnen eines Buttons
ich probier es mal aus. Danke erst mal.
|
Re: Welche Windows-Events zum Zeichnen eines Buttons
Liste der Anhänge anzeigen (Anzahl: 2)
Zitat:
Ich fand das Thema ganz interessant :stupid: und habe mal eine von TButton abgeleitete Komponente geschrieben, die BS_OWNERDRAW nutzt. Im Gegensatz zu WM_PAINT kriegt man WM_DRAWITEM/CN_DRAWITEM nämlich jedesmal, wenn der Button bzw. Teile davon neu gezeichnet werden müssen. Code siehe Anlage (OwnerDrawButton.pas), unterstützt Themes und Hot-Tracking. Ihr könnt den Button entweder komplett selbst zeichnen oder nur den Inhalt (den Rahmen übernimmt dann der Komponente). Als Beispiel ist im 2. Quelltext (ButtonWithImage.pas) eine abgeleitete Klasse drin, die einen Standard-Button mit Bild zeichnet (über Images/ImageIndex, so dass Actions funktionieren) - soll aber wie gesagt nur als Beispiel dienen, wie man daraus eigene Button-Klassen machen kann. // EDIT Hab' beide Dateien noch mal überarbeitet (hatte ja eh' noch niemand heruntergeladen). Übrigens habe ich gesehen, dass TBitBtn dasselbe Verfahren benutzt (die Quellen sind sogar ziemlich ähnlich), also könnte man auch den Subclassen bzw. als Vorlage benutzen. |
Re: Welche Windows-Events zum Zeichnen eines Buttons
Zitat:
schau es mir heut mal an. |
Re: Welche Windows-Events zum Zeichnen eines Buttons
Liste der Anhänge anzeigen (Anzahl: 1)
@Flocke
so, hab meine Button-Klasse mal umgebaut mit Deiner Variante. Soweit funktionierts Nur wird um die Buttons so eine Art "Dreckrand" gezeichnet. Tritt das bei Dir auch auf? (siehe Anhang) |
Re: Welche Windows-Events zum Zeichnen eines Buttons
Hmmm ... bei mir sehen die Buttons ganz normal aus. Zeichnet du den Rahmen selbst? Ein bisschen Quelltext wäre nicht schlecht.
|
Re: Welche Windows-Events zum Zeichnen eines Buttons
ich hab es mal mit Deinem Original-Button probiert, der selbe Effekt. Das einzige, was ich geändert habe, ist: Die Units ThemeMgr,ThemeSrv hinzugefügt, weil Delphi6. Vielleicht liegt das der Hund begraben.
|
Re: Welche Windows-Events zum Zeichnen eines Buttons
Wie sieht das Ganze denn aus, wenn du zum Testen mal das Standardlayout verwendest und kein spezielles Theme?
Häng' doch mal deinen aktuellen Quelltext an (oder per PN), dann kann ich das hier testen. |
Alle Zeitangaben in WEZ +1. Es ist jetzt 19:49 Uhr. |
Powered by vBulletin® Copyright ©2000 - 2025, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024 by Thomas Breitkreuz