Nicht in WM_PAINT zeichnen



  • dann ist es aber beim nächsten neuzeichnen nicht mehr da.



  • verdammt, stimmt ja... vergessen



  • Also, das funktioniert echt gut, main Zeichenprogramm (dank unglaublicher Benutzerunfreundlichkeit und schmerzhafter Bedinung Pain(t) genannt 😃 ) funktioniert einigermaßen.
    ABER: Wenn ich ein paar Sachen zeichne und das Fenster dann minimiere und wieder aufrufe ist alles weg 😞
    Nicht dass das bei meinen Zeichenkünsten schade ist aber ...
    Wie verhindere ich das?
    Gibt es dazu ein Event das ich abfangen kann?

    Grüße, Steve! 🤡



  • Wenn du alles in WM_PAINT zeichnest kommt alles wieder.

    Benutzt du jetzt doch GetDC und zeichnest direkt?



  • Was denke ich mal noch möglich wäre, wäre ein Memory DC wo du dann in WM_LBUTTONDOWN und anderen Nachrichten reinzeichnest und dieses Memory DC dann in WM_PAINT auf den DC deines Fensters blittest.



  • Also, ich mache es so:
    Wenn ich links klicke werden Koordinaten gespeichert, nach zweitem Klick wird dann, je nach Auswahl, ein Kreis oder ein Viereck (welches leider noch ein nicht transparentes "Innenleben" hat) gezeichnet, und zwar direkt im WM_PAINT.

    Die Idee mit diesem Memory DC klingt durchaus logisch.
    Verstehe ich das richtig: Ich male quasi in dieses DC und lade das bei Paint dann rein, oder?

    Und wie realisiere ich das?

    Grüße, Steve! 🤡



  • http://c-plusplus.net/forum/viewtopic.php?t=14713

    Das Anlegen des Memory-DCs kannst du dann z.B. bei WM_CREATE machen, freigeben bei WM_DESTORY (evtl. musst du noch irgendwie Größenänderungen des Fensters abfangen und dein Memory-DC ggf. vergrößern) - das BitBlt kommt dann in WM_PAINT 🙂



  • Also, ich habe das programmiert und es geht ... nur nicht richtig:
    Ich kann immer nur ein Viereck malen, beim zweiten löscht er das erste 😞
    Ich schicke mal meinen Quellcode (gekürzt):

    LRESULT ...
    {
        static HDC hdc, hdc2;
        switch(message)
        {
            case WM_PAINT:
            hdc = BeginPaint(hwnd, &ps);
            hdc2 = CreateCompatibleDC(hdc);
            hBM = CreateCompatibleBitmap(hdc, 800, 600);
            SelectObject(hdc2, hBM);
            //PaintAnweisungen
            BitBlt(hdc, 0, 0, 800, 600, hdc2, 0, 0, SRCCOPY);
            EndPaint(hwnd, &ps);
        }
    }
    

    ???
    Grüße, Steve! 🤡



  • Du darfst den DC nicht jedes Mal in WM_PAINT neu erstellen, erstell den einmal in WM_CREATE, so dass Du in WM_PAINT nur noch die BitBlt-Funktionalität hast. So, wie es jetzt ist erstellst Du in WM_PAINT ständig einen neuen DC, der aber auch nicht gelöscht wird. Vorgehensweise sollte also sein:

    WM_CREATE:  -MemoryDC erstellen
    WM_DESTROY: -MemoryDC zerstören
    WM_PAINT:   -MemoryDC in FensterDC blitten
    


  • Hm, ich habe jetzt echt viel rumprobiert, entweder er löscht wieder alle ausser das letzte (sprich ich kann nur einen Kreis usw zweichnen) oder er löscht beim minimieren/maximieren ...
    Kannst du mir mal ganz gekürzt bitte Code schicken?



  • Okay, ich glaube ich weiß wo ein Fehler stecken könnte, die Lösung ist mir nur noch schleierhaft:

    Bei dem Link den ich von euch bekommen habe steht folgender Code:

    HDC hDC = ...; // z.B. mit BeginPaint 
    HDC hDC2 = CreateCompatibleDC(hDC); 
    HBITMAP hBM = CreateCompatibleBitmap(hDC, cxClient, cyClient); 
    SelectObject(hDC2, hBM); 
    
    // Zeichenoperationen auf hDC2... 
    
    BitBlt(hDC, 0, 0, cxClient, cyClient, hDC2, 0, 0, SRCCOPY); 
    // Ein SelectObject(OldBitmap); ist imho nicht nötig 
    DeleteObject(hBM); 
    DeleteDC(hDC2);
    

    Gut, wenn ich nun
    HDC hdc = BeginPaint(...);
    schreibe dann mache ich das ja logischerweise in dem WM_PAINT. Wenn ich aber gleich danach das
    HDC hdc2 = CreaeCompatibleDC(hdc);
    mache dann löscht er es ja, wie schon geschrieben wurde, bei jedem PAINT und legt es neu an.
    Also wie behebe ich das jetzt?
    Nochmal das was ich habe:

    LRESULT ...
    {
        static HBITMAP hBM;
        static HDC hdc, hdc2;
        ...
        switch(message)
        {
        case WM_CREATE
        {
            ...
            hdc2 = CreateCompatibleDC(hdc); //da gibt es aber noch kein hdc (denke ich, also vielleicht das der Fehler)
            hBM = CreateCompatibleBitmap(hdc2, 800, 600);
            return 0;
        }
        case WM_PAINT:
        {
            hdc2 = BeginPaint(hwnd, &ps);
            SelectObject(hdc2, hBM);
            ...
            //Zeichnen
            ...
            BitBlt(hdc, 0, 0, 800, 600, hdc2, 0, 0, SRCCOPY);
            EndPaint(hwnd, &ps);
            return 0;
        }
    }
    


  • Versuch mal in WM_CREATE:

    HDC hdc = GetDC(hwnd);
    // und dann:
    hdc2 = CreateCompatibleDC(hdc);
    ReleaseDC(hwnd, hdc);
    


  • Hm, geht immer noch nicht 😞
    Immer bleibt nur das letzte wenn ich zb Fenster kleiner/größer mache ...



  • OK, hier:

    LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) {
    	static HDC hdc2;
    	static HBITMAP hBM;
    
    	switch (message) {
    		case WM_CREATE: {
    			HDC hdc = ::GetWindowDC(hWnd);
    			hdc2 = ::CreateCompatibleDC(hdc);
    			RECT r;
    			::GetClientRect(hWnd, &r);
    			hBM = CreateCompatibleBitmap(hdc, r.right - r.left, r.bottom - r.top);
    			::SelectObject(hdc2, hBM);
    			HBRUSH brush = (HBRUSH)GetStockObject(WHITE_BRUSH);
    			::FillRect(hdc2, &r, brush);
    			::DeleteObject(brush);
    			::ReleaseDC(hWnd, hdc);
    			break;
    		}
    		case WM_LBUTTONDOWN: {
    			::SelectObject(hdc2, ::GetStockObject(BLACK_PEN));
    			::LineTo(hdc2, LOWORD(lParam), HIWORD(lParam));
    			::InvalidateRect(hWnd, NULL, true);
    			break;
    		}
    		case WM_PAINT: {
    			PAINTSTRUCT ps;
    			::BeginPaint(hWnd, &ps);
    			RECT r;
    			::GetClientRect(hWnd, &r);
    			::BitBlt(ps.hdc, 0, 0, r.right - r.left, r.bottom - r.top, hdc2, 0, 0, SRCCOPY);
    			::EndPaint(hWnd, &ps);
    			break;
    		}
    		case WM_DESTROY: {
    			::DeleteDC(hdc2);
    			PostQuitMessage(0);
    			return 0;
    		}
    	}
    }
    

    Ist ein wenig durcheinander, aber ich musste auch erstmal schauen, wie das nochmal war. 🙂
    Wenn Du das Bitmap erstellst, dann solltest Du es aber nicht nur so groß erstellen, wie der Clientbereich ist, ansonsten wird das Fenster nicht ganz ausgefüllt, wenn Du es maximierst, am Besten nimmst Du hier ein Bitmap, welches so groß ist, wie die eingestellte Auflösung oder so.

    Hoffe, das hilft Dir ein wenig.



  • mantiz, du hast vergessen das Original-Objekt wieder reinzuselektieren.



  • Das Rect das GetClientRect() liefert, hat left und top übrigens immer auf 0 gesetzt 😉



  • @SelectObject: Es ging hier nur um die Funktionsweise, ich habe das nicht aus einem bestehenden Programm kopiert, sondern mal eben schnell zusammengeschrieben, so dass das gewollte funktioniert. Auf Feinheiten hab' ich keine Rücksicht genommen, dafür gibt es die MSDN und den Petzold. 😛

    @geeky:

    MSDN schrieb:

    Because client coordinates are relative to the upper-left corner of a window's client area, the coordinates of the upper-left corner are (0,0).

    Hast Recht, aber imo würde es mehr Sinn machen, wenn die ClientArea relativ zur Fensterposition angegeben würde, egal.

    Hab' jetzt sowieso keinen Bock mehr Sourcecode zu posten, jedes Mal, wenn ich Code poste wird dran rumgemeckert. Meistens handelt es sich um Codes, die aus dem Kontext gerissen sind, oder mal eben schnell zusammengeschrieben wurden, um die Vorgehensweise zu zeigen, nicht, um jmd. die ganze Arbeit und das Denken zu ersparen. Ich hab' zwar noch lange nicht so viel gepostet, wie manch anderer hier, aber so macht es einfach keinen Spass. 😞



  • Ja dann schreib am besten einen kleinen Hinweis dabei, das der Code noch nicht richtig fertig ist. Dann wird auch bestimmt nicht soviel gemerkt. 😉
    Das Problem ist das die meisten das einfach abkopieren und dann haben die auch den Fehler drin.



  • Naja, wenn hier Code gepostet wird, dann ist dieser ja eigentlich dazu gedacht, dass man diesen ohne zu überlegen kopiert und verwendet, sondern eher, gewisse Dinge besser zu verstehen, die man nicht so gut mit Worten beschreiben kann bzw. der besseren Veranschaulichung. Wenn jmd. den Code einfach nur kopiert, ohne zu verstehen, was da abgeht bzw. ohne sich selbst Gedanken dazu zu machen und sich näher damit zu beschäftigen, dann ist dieser jmd. auch selbst Schuld, wenn nicht alles einwandfrei funktioniert, oder evtl. Speicher-Leaks entstehen, oder ... oder.

    Mir hat es auch schon des öfteren geholfen, wenn jmd. etwas Code gepostet hat, damit ich etwas besser verstehe, aber ich würde mich hüten den Code einfach so zu übernehmen. Sorry, aber dann hat man es auch nicht besser verdient. Nur meine Meinung.



  • Hm, also ich muss mantiz mal ein bisschen verteidigen. Am Quellcode von ihm rumzumeckern bringt echt nichts, ich bat nämlich echt nur um den Code damit ich endlich weiß wie es gehen könnte, ihn dumm zu kopieren, das mache ich nicht, so schlau bin SOGAR ICH!
    Hoho!
    Also bitte hör nicht auf Quellcode zu posten, ich tu mir damit viel leichter als wenn mir wer sagt wie es geht ... weil Code verstehe ich recht leicht, ein bisschen noch Googeln und MSDN und fertig!
    Na jedenfalls danke schön! Ich schaue mir das gleich mal an ...

    Grüße, Steve! 🤡


Anmelden zum Antworten