Registriert seit: 2. Dez 2003
Ort: Berlin/Eschede
481 Beiträge
Delphi 7 Professional
|
Re: Welche Windows-Events zum Zeichnen eines Buttons
9. Dez 2005, 12:26
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:
// 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;
Dazu noch der besagte Funktionshook hat mir recht passable Ergebnisse gebracht. Ist allerdings größtenteils ungetestet. Es gibt einfach zuviele Anwendungen und Fälle.
Wer später bremst ist eher tot.
|