DC muss neu gezeichnet werden, wie?



  • Hallo,

    ich hab eben mal testweise ein beliebiges Fenster über mein Fenster rüber- und wieder runtergezogen.
    Dabei musste ich feststellen, dass meine DCs danach mal halb noch da sind, mal garnicht, mal komplett.
    Die Frage ist, wie kann ich explizit anordern WM_PAINT in diesem Moment neu aufzurufen?

    Gruß Max



  • InvalidateRect ist die Funktion deiner Wahl.



  • Wenn etwas über Dein Fenster gezogen wird und wieder weg geht, wird ein WM_PAINT automatisch ausgelöst!

    Du zeichnest vermutlich *nicht* in WM_PAINT....

    Ansonsten siehe: InvalidateRect



  • Danke, die kenne ich, aber wann bzw. wo wende ich die an?

    Gruß, Max

    PS: Das ist die problematische WNDPROC:

    LRESULT CALLBACK WndButtonEx(HWND hWnd,UINT msg,WPARAM wParam,LPARAM lParam)
    {
    	TRACKMOUSEEVENT MouseEvent;
    	HDC hDC,hcDC;
    	PAINTSTRUCT ps;
    	HBITMAP hBitmapOld,hBitmapNew;
    
    	static HINSTANCE hInstance = (HINSTANCE)GetWindowLong(hWnd,GWL_HINSTANCE);
    
    	WNDPROC* WndProc = (WNDPROC*)GetWindowLong(hWnd,GWL_USERDATA);
    
    	switch (msg)
    	{
    		case WM_PAINT:
    		{
    			hBitmapNew = LoadBitmap(hInstance,MAKEINTRESOURCE(GetWindowTextInteger(hWnd)));
    			hDC = BeginPaint(hWnd,&ps);
    			Fill(hWnd,RGB(255,255,255));
    			hcDC = CreateCompatibleDC(hDC);
    			hBitmapOld = (HBITMAP)SelectObject(hcDC,hBitmapNew);
    			BitBlt(hDC,3,3,22,22,hcDC,0,0,SRCCOPY);
    			SelectObject(hcDC,hBitmapOld);
    			RoundedRect(hDC,0,0,27,27,RGB(150,150,150));
    			EndPaint(hWnd,&ps);
    			DeleteObject(hBitmapNew);
    			DeleteDC(hcDC);
    			break;
    		}
    		case WM_MOUSELEAVE:
    		{
    			InvalidateRect(hWnd,NULL,true);
    			break;
    		}
    		case WM_MOUSEMOVE:
    		{
    			MouseEvent.cbSize      = sizeof(TRACKMOUSEEVENT);
    			MouseEvent.dwFlags     = TME_HOVER|TME_LEAVE;
    			MouseEvent.dwHoverTime = HOVER_DEFAULT;
    			MouseEvent.hwndTrack   = hWnd;
    			_TrackMouseEvent(&MouseEvent);
    			hDC = GetWindowDC(hWnd);
    			RoundedRect(hDC,0,0,27,27,RGB(0,0,0));
    			ReleaseDC(hWnd,hDC);
    			break;
    		}
    	}
    	return CallWindowProc(*WndProc,hWnd,msg,wParam,lParam);
    }
    


  • Denke in deiner Mousemove.



  • Danke für die Idee, aber wenn ich in WM_MOUSEMOVE InvalidateRect() nutze, ist der Hover-Effekt vereitelt, weil WM_PAINT dann direkt nach jeder Mausbewegung wieder ausgeführt wird und somit der Hover-Effekt wieder überzeichnet wird.

    lg Max



  • du benutzt doch WM_PAINT. Die wird automatisch ausgelöst da bräuchtest du theoretisch kein InvalidateRect()



  • WM_PAINT + subclassing = problem



  • MaDsTyLe schrieb:

    Danke für die Idee, aber wenn ich in WM_MOUSEMOVE InvalidateRect() nutze, ist der Hover-Effekt vereitelt, weil WM_PAINT dann direkt nach jeder Mausbewegung wieder ausgeführt wird und somit der Hover-Effekt wieder überzeichnet wird.

    lg Max

    Das heißt du willst etwas neues Zeichnen, aber das alte nicht löschen?! 😕 Bin ein wenig verwirrt...

    Sonst zeichne doch nur den Teil neu, welcher neu gezeichnet werden soll... wozu gibts nen RECT bei invalidaterect?


  • Mod

    Alles Zeichnen sollte in WM_PAINT erfolgen. Punkt.

    Sorge dafür das in WM_PAINT einfach alle Fälle (inkl. Hoover Effekt) behandelt werden.



  • Gerne, klingt auch sehr strikt und korrekt, aber wie kann ich den Hover-Status in der WM_PAINT "abfangen"?

    Danke, für Eure Antworten! 🙂

    Gruß, Max

    PS@Speedy_92:
    Wo siehst Du ein RECT? Der zweite Parameter ist das RECT, der ist NULL.
    Was im Moment passiert ist folgendes:
    Als erstes wird mit WM_PAINT gezeichnet.
    Wenn der Hover-Effekt eintritt, wird etwas ÜBER den bestehenden DC gezeichnet.
    Wenn der Hover-Effekt austritt, wird WM_PAINT wieder aufgerufen und alles sieht aus wie vorher.


  • Mod

    Blödsinn! Du sollst keinen Hoverstatus in WM_PAINT abfangen.

    - Du bekommst eine Nachricht über WM_MOUSEMOVE (Hoover)
    - Du setzt ein Flag oder einen Status über den Zustand Deines Controls
    - Du führst einen Invalidate durch
    - WM_PAINT trifft ein
    - Du findest den Zustand in einem Flag/Status Deines Controls und zeichnest entsprechende (Hovver oder eben nicht)

    Keine Alternative ist wenn Du auch einfach kontrollierst wo die Maus sich in WM_PAINT gerade befindet. Dieses Verfahren ist unsicher, denn ein Teil Deines Controls könnte neu zu zeichnen sein und in der Zwischenzeit die Maus in das Fentser gewandert sein. Die Folge: Dein Control wird falsch gezeichnet.



  • Blödsinn!

    Sorry, bin 16, hab Deine Erfahrung nich ...

    Auch was Du über WM_MOUSEMOUVE sagst, leuchtet mir ein.
    Allerdings habe ich das in der Vergangenheit so geregelt, weil mit doch schließlich erst mit WM_MOUSEMOVE den _TrackMouseEvent machen muss (?).
    Wenn ich dies tue und dann WM_MOUSEHOVER und WM_MOUSELEAVE behandle, so tritt WM_MOUSEHOVER immer verspätet ein, weil natürlich erst WM_MOUSEMOVE behandelt wird.
    Schön sieht das nicht aus...

    Frage: Muss ich _TrackMouseEvent in der WM_MOUSEMOVE aufrufen, oder geht das auch von "außerhalb"?

    Zu dem Flag:
    Genau das habe ich gemacht, doch wenn in WM_MOUSEMOVE InvalidateRect aufgerufen wird, flimmert der button heftig beim Drüberfahren.
    Liegt wohl auch daran, dass ich WM_MOUSEHOVER nicht, und WM_MOUSEMOVE falsch nutze...

    Danke, für die Hilfe!

    Gruß, Max


  • Mod

    Das Flackern entsteht evtl. dadurch, dass Dein Button auch kein DoubleBuffering für das Zeichnen verwendet. Oft genug ist schon das Problem, dass WM_ERASEBKGND ausgeführt wird und der WM_PAINT erst danach erfolgt.

    Ist das ein eigener Button?
    Wie sieht Dein Code aus?
    Evtl. Einfach nicht nur Invalidate machen, sondern mit RedrawWindow sofort das Neuzeichnen erzwingen.



  • Oder auch nur InvalidateRect aufrufen, wenn sich der Hover-Status geändert hat, die Maus also vorher nicht über dem Control war.


  • Mod

    Badestrand schrieb:

    Oder auch nur InvalidateRect aufrufen, wenn sich der Hover-Status geändert hat, die Maus also vorher nicht über dem Control war.

    Guter Hinweis!



  • Hmmm, danke nochmals für Eure Antworten.

    Werde ich alles umsetzen, doch gerade stellt sich mir ein anderes Problem.

    Ich will die WNDPROC mehrmals benutzen, dh. mehrere Buttons erstellen.

    Wenn ich aber ein Flag setze für den hover/hot-state, dann muss dieses static sein.
    Wenn es aber static ist, wird jede neue Zuweisung gleich für alle anderen Buttons mitgeändert -> Desaster.

    Mir fällt spontan ein static std::vector<bool> als Lösungsansatz ein, bin mir aber nicht sicher, ob das wirklich die sinnvollste Idee, daher frag ich ...

    Nochmals, danke, danke!

    Gruß, Max



  • Besser du erstellst eine Button-Klasse mit einer flags-Membervariable. Wie du die WndProc da nicht-statisch reinbekommst, dazu gibt's hier im Forum etliche Threads, einfach mal suchen, evtl steht auch was in der FAQ.


Log in to reply