Außerhalb von WM_PAINT zeichnen



  • Hi,
    ich habe vor außerhalb der WM_PAINT etwas in mein Fenster zu zeichnen (z.B. beim Klicken auf einen Button oder beim Klicken in das Fenster (wie bei MS Paint o.ä)). Das funktioniert auch prima, allerdings verschwindet das Gezeichnete, wenn ich das Fenster minimiere/maximiere (ist ja auch klar, da WM_PAINT es nicht neu zeichnet).
    Jetzt ist meine Frage: Wie kann ich den, vom Benutzer erzeugten, Inhalt des Fensters speichern und in WM_PAINT neu zeichnen lassen?

    Ich hoffe ihr versteht mein Problem und könntet mir helfen (wenn es möglich ist).

    gruß



  • Douny schrieb:

    Das funktioniert auch prima, allerdings verschwindet das Gezeichnete, wenn ich das Fenster minimiere/maximiere (ist ja auch klar, da WM_PAINT es nicht neu zeichnet).

    Das kann ich nicht nachvollziehen.
    Wenn ein Fenster vergrößert wird, wird immer ein WM_PAINT ausgelöst!

    Beim Fenster minimieren kommt natürlich kein WM_PAINT mehr, wozu auch, wenn sowieso nichts mehr zu sehen ist?

    Irgendwas hast Du falsch konstruiert...

    Du kannst ein WM_PAINT erzwingen indem Du ein InvalidateRect() für das betreffende Fenster aufrufst. Trotzdem, das ist nicht der richtige Weg!

    Verwendest Du das obligatorische BeginPaint() und EndPaint() Gespann bei der WM_PAINT-Nachricht?

    Martin



  • erstelle einfach einen globalen DC (z.B. während WM_CREATE) in dem du dann alles Zeichnest. Während der Abarbeitung von WM_PAINT kopierst(BitBlt) du diesen dann einfach in den durch wParam übergebenen DC.



  • Tschuldige ich meinte natürlich nicht beim minimieren sondern beim wiederherstellen nachdem es minimiert war (da kommt ja eine WM_PAINT Nachricht).
    Die Möglichkeit über InvalidateRect() ein WM_PAINT zu erzwingen ist mir bekannt und ich verwende auch das BeginPaint() EndPaint() Konstrukt.
    Allerdings ist das nicht meine Frage.
    Ich versuche noch mal mein Problem etwas näher zu erläutern:
    Ich möchte als Reaktion auf einen Mausklick im ClientArea etwas zeichnen lassen (zb eine Linie mit LineTo). Den nun veränderen Inhalt des Fensters möchte ich irgendwie speichern oder an WM_PAINT übergeben, sodass er bei jedem Aufruf von WM_PAINT neu gezeichnet wird (inclusive der erstellten Linie).
    Also bisher zeichnet WM_PAINT ja (zb beim maximieren) wieder eine weiße Fläche ohne die vorher erzeugte Linie (um die Linie in WM_PAINT zu zeichnen müsste ich ja dort auch ein LineTo aufrufen). Allerdings will ich ja während der Laufzeit eine Linie beliebig erstellen(zb von A nach B - Klick mit der Maus zuerst bei A und dann bei B).
    Wie kann ich also den geänderten Inhalt des Fensters speichern um ihn dann so wie er aktuell ist bei jeder WM_PAINT zeichnen zu lassen.

    Ich hoffe ich habe es iwie verständlich formulieren können^^
    Gruß

    Edit:
    Okay an BitBlt dachte ich auch schon, allerdings weiß ich nicht so genau wie ich das anwenden soll 🙄 als Beispielcode hab ich gerade mal das hier geschrieben (Die WndProc - hDCGlobal ist global deklariert)

    LRESULT CALLBACK WndProcMain(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
    {
    	HDC hDC;
    	PAINTSTRUCT ps;
    
    	switch(message)
    	{
    	case WM_LBUTTONUP:
    		hDCGlobal = GetDC(hWnd);
    		SetPixel(hDCGlobal, LOWORD(lParam), HIWORD(lParam), RGB(255, 0, 0));
    		ReleaseDC(hWnd, hDCGlobal);
    		return 0;
    	case WM_PAINT:
    		hDC = BeginPaint(hWnd, &ps);
    		BitBlt(hDC, 0, 0, 800, 600, hDCGlobal, 0, 0, SRCCOPY);
    		EndPaint(hWnd, &ps);
    		return 0;
    	case WM_DESTROY:
    		PostQuitMessage(0);
    		return 0;
    	}	
    	return DefWindowProc(hWnd, message, wParam, lParam);
    }
    

    Allerdings verstehe ich nicht wie du das mit dem DC in WParam meinst (so wie ich das geschrieben habe funktioniert es schon mal nicht^^)



  • Kann es sein, daß die Linien (die Du meinst) nichts anderes als Selektionsrahmen sind? (auch unter dem Begriff "Gummi-Rechtecke" bekannt)

    In der Hoffnung, daß dies so ist, hier ein paar Links:
    http://www.c-plusplus.net/forum/viewtopic-var-t-is-233462-and-start-is-0-and-postdays-is-0-and-postorder-is-asc.html
    http://www.win-api.de/tut10.html
    http://www.programmersheaven.com/mb/windows/104684/104684/drawing-a-selection-box-on-screen-with-the-mouse---example-code/

    Sorry, ich muß mich erstmal ausklinken, da es doch recht spät ist...
    Morgen evtl. mehr, ok?
    Martin



  • Nene keine Selektionsrahmen sondern einfach ne gezeichnete Linie (oder ein Punkt ->siehe Code SetPixel) oder egal was... einfach irgendwelche grafischen Ausgaben im Client Area des Fensters, die auf eine Nachricht wie zb WM_LBUTTONUP erscheinen sollen und dann via WM_PAINT immer wieder neu gezeichnet werden sollen (auch wenn das Programm beim Start noch nicht weiß wo diese Grafiken später mal sein werden). Ich weiß nicht so recht wie ich das jetzt formulieren soll^^

    Die Idee mit BitBlt geht in die Richtung wo ich hin will (also vom Effekt her) aber ich weiß nicht wie ich das umsetzen soll 🙄

    Kurz gesagt: wenn eine WM_PAINT Nachricht eintrifft soll das Fenster so wie es ist (inclusive der durch den Benutzer hinzugefügten Linien oä) neu gezeichnet werden.
    Also die Linien sollen nicht wieder verschwinden wenn man das Fenster maximiert oder ein anderes Fenster darüber schiebt.

    gruß



  • return 0? Muss da nicht ein Break stehen?



  • _Luckie schrieb:

    return 0? Muss da nicht ein Break stehen?

    return 0, oder break.



  • @jwb:
    @_Luckie:
    Wenn WM_PAINT verarbeitet wird, muß zum Schluß return(0); angewendet werden.
    Steht so in der MSDN. Punkt.
    Auf keinen Fall mit einem break; und damit i.d.R. Weiterleitung an DefWindowProc(...);

    @Douny:
    Ich glaube, jetzt hab ichs verstanden: Du möchtest sowas wie ein gewöhnliches Malprogramm realisieren (egal ob ein Punkt, Linie oder Rechteck gezeichnet wird)? Richtig?

    Dann mußt Du alle neuen Informationen was Zeichenelemente betrifft irgendwo zwischenspeichern.
    Und WM_PAINT zeichnet dann anhand dieser gespeicherten Informationen neu.
    Es gibt mehrere Möglichkeiten für die Art der Speicherung, hier zwei Möglichkeiten:
    a) Du zeichnest alle neuen Elemente in einen (unsichtbaren) Bitmap und malst bei WM_PAINT per BitBlt() diesen Bitmap auf den Schirm.
    b) Du speicherst für jedes neue Element ihre Koordinaten (und Farbe, Dicke, ... usw. ) in einer Liste ab. Bei WM_PAINT wird dann diese Liste abgearbeitet und durch übliche GDI-Funktionen auf den Schirm gemalt.

    Aber Achtung, ein Hinweis: Ein Monitor mit z.B. 1920x1200 Auflösung hat in der Vollbilddarstellung 2.304.000 Pixel, bei 32bit Farbtiefe sind das ca. 10 MByte Bitmap!

    Martin

    P.S.: Allgemeine Grundlagen für WM_PAINT:
    "Using the WM_PAINT Message" http://msdn.microsoft.com/en-us/library/dd145193(VS.85).aspx



  • Jetzt reden wir vom gleichen Problem^^ so was in die Richtung dachte ich mir schon... werd das dann mal ausprobieren (per Bitmap und BitBlt).
    Mal schauen obs was wird*g*
    Mit der Bitmapgröße werd ich noch meinen Spaß haben, mal sehn was mein Rechner so her gibt:P

    Danke und Gruß


Anmelden zum Antworten