AGB  ·  Datenschutz  ·  Impressum  







Anmelden
Nützliche Links
Registrieren
Zurück Delphi-PRAXiS Programmierung allgemein GUI-Design mit VCL / FireMonkey / Common Controls Delphi Welche Windows-Events zum Zeichnen eines Buttons
Thema durchsuchen
Ansicht
Themen-Optionen

Welche Windows-Events zum Zeichnen eines Buttons

Ein Thema von sh17 · begonnen am 9. Dez 2005 · letzter Beitrag vom 20. Dez 2005
Antwort Antwort
Seite 1 von 2  1 2      
Benutzerbild von sh17
sh17

Registriert seit: 26. Okt 2005
Ort: Radebeul
1.643 Beiträge
 
Delphi 11 Alexandria
 
#1

Welche Windows-Events zum Zeichnen eines Buttons

  Alt 9. Dez 2005, 11:20
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:
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;
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.

Meine Frage: Welche Windows-Ereignisse gibt es noch, auf die ich das Zeichnen anwerfen muss?
Sven Harazim
--
  Mit Zitat antworten Zitat
Benutzerbild von Luckie
Luckie

Registriert seit: 29. Mai 2002
37.621 Beiträge
 
Delphi 2006 Professional
 
#2

Re: Welche Windows-Events zum Zeichnen eines Buttons

  Alt 9. Dez 2005, 12:05
MSDN-Library durchsuchenInvalidateRect erzwingt ein Neuzeichnen des betreffenden Fensters.
Michael
Ein Teil meines Codes würde euch verunsichern.
  Mit Zitat antworten Zitat
Vjay

Registriert seit: 2. Dez 2003
Ort: Berlin/Eschede
481 Beiträge
 
Delphi 7 Professional
 
#3

Re: Welche Windows-Events zum Zeichnen eines Buttons

  Alt 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.
  Mit Zitat antworten Zitat
Benutzerbild von sh17
sh17

Registriert seit: 26. Okt 2005
Ort: Radebeul
1.643 Beiträge
 
Delphi 11 Alexandria
 
#4

Re: Welche Windows-Events zum Zeichnen eines Buttons

  Alt 9. Dez 2005, 13:06
ich probier es mal aus. Danke erst mal.
Sven Harazim
--
  Mit Zitat antworten Zitat
Benutzerbild von Flocke
Flocke

Registriert seit: 9. Jun 2005
Ort: Unna
1.172 Beiträge
 
Delphi 10.2 Tokyo Professional
 
#5

Re: Welche Windows-Events zum Zeichnen eines Buttons

  Alt 10. Dez 2005, 02:15
Zitat von Vjay:
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.
Genau da liegt das Problem - ein TButton ist eben kein natives Delphi-Control sondern eine von Windows vorgegebene Fensterklasse. Da kann man das Zeichnen nicht erweitern, sondern müsste es komplett neu schreiben.

Ich fand das Thema ganz interessant 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.
Angehängte Dateien
Dateityp: pas buttonwithimage_104.pas (7,2 KB, 45x aufgerufen)
Dateityp: pas ownerdrawbutton_951.pas (13,5 KB, 88x aufgerufen)
Volker
Besucht meine Garage
Aktuell: RtfLabel 1.3d, PrintToFile 1.4
  Mit Zitat antworten Zitat
Benutzerbild von sh17
sh17

Registriert seit: 26. Okt 2005
Ort: Radebeul
1.643 Beiträge
 
Delphi 11 Alexandria
 
#6

Re: Welche Windows-Events zum Zeichnen eines Buttons

  Alt 12. Dez 2005, 06:16
Zitat:
Hab' beide Dateien noch mal überarbeitet (hatte ja eh' noch niemand heruntergeladen).
habs runtergeladen
schau es mir heut mal an.
Sven Harazim
--
  Mit Zitat antworten Zitat
Benutzerbild von sh17
sh17

Registriert seit: 26. Okt 2005
Ort: Radebeul
1.643 Beiträge
 
Delphi 11 Alexandria
 
#7

Re: Welche Windows-Events zum Zeichnen eines Buttons

  Alt 16. Dez 2005, 13:51
@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)
Miniaturansicht angehängter Grafiken
aufnahme1_822.jpg  
Sven Harazim
--
  Mit Zitat antworten Zitat
Benutzerbild von Flocke
Flocke

Registriert seit: 9. Jun 2005
Ort: Unna
1.172 Beiträge
 
Delphi 10.2 Tokyo Professional
 
#8

Re: Welche Windows-Events zum Zeichnen eines Buttons

  Alt 16. Dez 2005, 16:51
Hmmm ... bei mir sehen die Buttons ganz normal aus. Zeichnet du den Rahmen selbst? Ein bisschen Quelltext wäre nicht schlecht.
Volker
Besucht meine Garage
Aktuell: RtfLabel 1.3d, PrintToFile 1.4
  Mit Zitat antworten Zitat
Benutzerbild von sh17
sh17

Registriert seit: 26. Okt 2005
Ort: Radebeul
1.643 Beiträge
 
Delphi 11 Alexandria
 
#9

Re: Welche Windows-Events zum Zeichnen eines Buttons

  Alt 19. Dez 2005, 09:41
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.
Sven Harazim
--
  Mit Zitat antworten Zitat
Benutzerbild von Flocke
Flocke

Registriert seit: 9. Jun 2005
Ort: Unna
1.172 Beiträge
 
Delphi 10.2 Tokyo Professional
 
#10

Re: Welche Windows-Events zum Zeichnen eines Buttons

  Alt 19. Dez 2005, 16:42
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.
Volker
Besucht meine Garage
Aktuell: RtfLabel 1.3d, PrintToFile 1.4
  Mit Zitat antworten Zitat
Antwort Antwort
Seite 1 von 2  1 2      


Forumregeln

Es ist dir nicht erlaubt, neue Themen zu verfassen.
Es ist dir nicht erlaubt, auf Beiträge zu antworten.
Es ist dir nicht erlaubt, Anhänge hochzuladen.
Es ist dir nicht erlaubt, deine Beiträge zu bearbeiten.

BB-Code ist an.
Smileys sind an.
[IMG] Code ist an.
HTML-Code ist aus.
Trackbacks are an
Pingbacks are an
Refbacks are aus

Gehe zu:

Impressum · AGB · Datenschutz · Nach oben
Alle Zeitangaben in WEZ +1. Es ist jetzt 21:24 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