Double Buffering



  • Hi,

    Wie kann ich in der WinAPI ein DoubleBuffering realisieren? Hat jemand dazu vielleicht ein Tutorial oder den passenden Code. Ich habe es jetzt schon damit probiert, in ein Bitmap zu schreiben und dieses nach dem Schreiben auf dem Bildschirm darzustellen, aber das Blitten des 2. Bitmaps funktioniert nicht.





  • Hi,

    Warum funktioniert dann folgender Code nicht? Er sollte eigentlich den Wert von i ausgeben, also hochzählen, jedoch gibt er immer nur das erste Bitmap aus, und das, obwohl die Funktion Paint in jedem Durchlauf aufgerufen wird.

    Kann sich das jemand mal ansehen?

    #include <windows.h>
    #include <iostream>
    
    using namespace std;
    
    HFONT fnt;
    char caption[] = "Hallo";
    int i = 0;
    
    LRESULT CALLBACK wndProc (HWND, UINT, WPARAM, LPARAM);
    
    //das ist die eigentliche Methode
    
    void Paint(HWND wnd, LPPAINTSTRUCT ps)
    {
    	RECT rc;
        HDC hdcMem;
        HBITMAP bmMem, bmOld;
        HBRUSH brBkGnd;
    	HFONT fntOld;
    
    	i++;
    	sprintf (caption, "%2d", i);
    
        GetClientRect(wnd, &rc);
    
        hdcMem = CreateCompatibleDC(ps->hdc);
    
        bmMem = CreateCompatibleBitmap (ps->hdc, rc.right - rc.left, rc.bottom - rc.top);
    
    	SelectObject (hdcMem, bmMem);
    
        brBkGnd = CreateSolidBrush (GetSysColor (COLOR_WINDOW));
        FillRect (hdcMem, &rc, brBkGnd);
        DeleteObject (brBkGnd);
    
        if (fnt) 
    	{
    		SelectObject (hdcMem, fnt);
        }
    
        SetBkMode (hdcMem, TRANSPARENT);
        SetTextColor (hdcMem, GetSysColor (COLOR_WINDOWTEXT));
        DrawText (hdcMem, caption, -1, &rc, DT_CENTER);
    
        if (fntOld)
    	{
            SelectObject (hdcMem, fntOld);
        }
    
        BitBlt (ps->hdc, rc.left , rc.top, rc.right - rc.left, rc.bottom - rc.top, hdcMem, 0, 0, SRCCOPY);
    
        SelectObject(hdcMem, bmOld);
        DeleteObject(bmMem);
        DeleteDC(hdcMem);
    
    }
    
    //nur falls das mal jemand testen will
    
    int WINAPI WinMain (HINSTANCE instance, HINSTANCE prevInstance, PSTR cmdLine, int cmdShow)
    {
    	static TCHAR appName[] = TEXT ("HelloWin");
    	HWND     wnd;
    	MSG      msg;
    	WNDCLASS wndclass;
    
    	wndclass.style         = CS_HREDRAW | CS_VREDRAW;
    	wndclass.lpfnWndProc   = wndProc;
    	wndclass.cbClsExtra    = 0;
    	wndclass.cbWndExtra    = 0;
    	wndclass.hInstance     = instance;
    	wndclass.hIcon         = LoadIcon (NULL, IDI_APPLICATION);
    	wndclass.hCursor       = LoadCursor (NULL, IDC_ARROW);
    	wndclass.hbrBackground = (HBRUSH) (COLOR_BTNFACE + 1);
    	wndclass.lpszMenuName  = NULL;
    	wndclass.lpszClassName = appName;
    
    	if (!(RegisterClass (&wndclass)))
    	{
    		MessageBox (NULL, "Programm-Fehler!", "Fehler!", MB_ICONERROR);
    		return 0;
    	}
    
    	wnd = CreateWindow (appName,
    						 TEXT ("Sort-Algorithmen"),
    						 WS_OVERLAPPED | WS_MINIMIZEBOX | WS_SYSMENU,
    						 CW_USEDEFAULT,
    						 CW_USEDEFAULT,
    						 CW_USEDEFAULT,
    						 CW_USEDEFAULT,
    						 NULL,
    						 NULL,
    						 instance,
    						 NULL);
    
    	ShowWindow (wnd, cmdShow);
    	UpdateWindow (wnd);
    
        PAINTSTRUCT ps;
    
    	while (true)
    	{
    		if (PeekMessage (&msg, NULL, 0, 0, PM_REMOVE))
    		{
    			if (msg.message == WM_QUIT)
    			{
    				break;
    			}
    			TranslateMessage (&msg);
    			DispatchMessage (&msg);
    
    		}
    		BeginPaint(wnd, &ps);
    		Paint(wnd, &ps);
    		EndPaint(wnd, &ps);
    	}
    	return msg.wParam;
    }
    
    LRESULT CALLBACK wndProc (HWND wnd, UINT msg, WPARAM wParam, LPARAM lParam)
    {
        switch(msg) 
        {
    		case WM_PAINT:
    			break;
    
    		case WM_DESTROY:
    			PostQuitMessage (0);
    			return 0;
    
    	         default:
    			return DefWindowProc(wnd, msg, wParam, lParam);
    			break;
        }
    	return NULL;
    
    }
    


  • Du bearbeitest WM_PAINT falsch. Entweder musst diese Nachricht wirklich verarbeiten (mit BeginPaint/EndPaint) oder sie an DefWindowProc weiterreichen.
    Deine Lösung führt zu einer Endlosschleife.

    BeginPaint/EndPaint darf außerdem nur bei der Beabeitung von WM_PAINT aufgerufen werden, niemals woanders. Deine Aufrufe in WinMain führen zu undefiniertem Verhalten.

    Vielleicht solltest du dir erstmal ein paar Grundlagen der WinAPI anlesen. Dann wüsstest du, dass man für dein Problem z.B. einen Timer benutzen könnte. Dieser erhöht jedesmal i um eins und ruft dann InvalidateRect auf, damit das Fenster neugezeichnet wird.


Anmelden zum Antworten