Thread: A window hangs/freezes or repaints itself

  1. #1
    Registered User
    Join Date
    Apr 2008
    Posts
    610

    A window hangs/freezes or repaints itself

    Wrote a code to draw a circle with brushes using Ellipse object. The program compiles and run but the output windows gets very slow (trying to minimize or drag it) or freezes.. When i minimize, the circle will be left on the actual screen while the window is minimized and restoring from minimize takes forever... This actually slows the entire PC

    I tried using two functions to draw "ReallySimpleCircle" and "Win32APIGDICircle".. The Win32APIGDICircle is the one which gives these problems..

    Code:
    // Resources.cpp : Defines the entry point for the console application.
    //
    
    #include "stdafx.h"
    
    #define _WIN32_WINNT 0x500
    #include <windows.h>
    
    #include <math.h>
    
    #pragma hdrstop
    
    //---------------------------------------------------------------------------
    
    #pragma argsused
    //---------------------------------------------------------------------------
    
    #define REALLYSIMPLE_CIRCLE_COLOR RGB (0, 128, 255)
    
    const char *ClsName = "FundApp";
    const char *WndName = "Resources Fundamentals";
    LRESULT CALLBACK WndProcedure(HWND hWnd, UINT uMsg,
    							  WPARAM wParam, LPARAM lParam);
    void DrawRectangle(HWND hWnd);
    void ReallySimpleCircle (HDC hdc, LONG radius, POINT ptCenter, COLORREF crColor);
    void Win32APIGDICircle (HDC hdc, LONG radius, POINT ptCenter, int R, int G, int B);
    
    //---------------------------------------------------------------------------
    INT WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
    				   LPSTR lpCmdLine, int nCmdShow)
    {
    	MSG        Msg;
    	HWND       hWnd;
    	WNDCLASSEX WndClsEx;
    
    	// Create the application window
    	WndClsEx.cbSize        = sizeof(WNDCLASSEX);
    	WndClsEx.style         = CS_HREDRAW | CS_VREDRAW;
    	WndClsEx.lpfnWndProc   = WndProcedure;
    	WndClsEx.cbClsExtra    = 0;
    	WndClsEx.cbWndExtra    = 0;
    	WndClsEx.hIcon         = LoadIcon(NULL, IDI_APPLICATION);
    	WndClsEx.hCursor       = LoadCursor(NULL,IDC_ARROW);
    	WndClsEx.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH);
    	WndClsEx.lpszMenuName  = NULL;
    	WndClsEx.lpszClassName = ClsName;
    	WndClsEx.hInstance     = hInstance;
    	WndClsEx.hIconSm       = LoadIcon(NULL, IDI_APPLICATION);
    
    	// Register the application
    	RegisterClassEx(&WndClsEx);
    
    	// Create the window object
    	hWnd = CreateWindowEx(0,
    		ClsName,
    		WndName,
    		WS_OVERLAPPEDWINDOW,
    		CW_USEDEFAULT,
    		CW_USEDEFAULT,
    		CW_USEDEFAULT,
    		CW_USEDEFAULT,
    		NULL,
    		NULL,
    		hInstance,
    		NULL);
    
    	// Find out if the window was created
    	if( !hWnd ) // If the window was not created,
    		return FALSE; // stop the application
    
    	// Display the window to the user
    	ShowWindow(hWnd, nCmdShow);// SW_SHOWNORMAL);
    	UpdateWindow(hWnd);
    
    	// Decode and treat the messages
    	// as long as the application is running
    	while( GetMessage(&Msg, NULL, 0, 0) )
    	{
    		TranslateMessage(&Msg);
    		DispatchMessage(&Msg);
    	}
    
    	return Msg.wParam;
    }
    //---------------------------------------------------------------------------
    LRESULT CALLBACK WndProcedure(HWND hWnd, UINT Msg,
    							  WPARAM wParam, LPARAM lParam)
    {
    	// Circle variables
    	POINT ptCenter = {450,300};
    	HDC hdc = GetDC(hWnd);
    	COLORREF crColor;
    
    	
    	// Handle messagse
    	switch(Msg)
    	{
    		case WM_PAINT:
    			{		
    			//DrawRectangle(hWnd);
    			//ReallySimpleCircle (hdc, 50, ptCenter, REALLYSIMPLE_CIRCLE_COLOR);
    			Win32APIGDICircle (hdc, 200, ptCenter, 0, 255, 128);
    			break;
    			} 
    		case WM_DESTROY:
    			PostQuitMessage(WM_QUIT);
    		break;
    		default:
    		// Process the left-over messages
    		return DefWindowProc(hWnd, Msg, wParam, lParam);
    	}
    	// If something was not done, let it go
    	return 0;
    }
    
    // Win32API GDI circle:
    void Win32APIGDICircle (HDC hdc, LONG radius, POINT ptCenter, int R, int G, int B)
    {
    	SelectObject (hdc, GetStockObject (DC_BRUSH));
    	SetDCBrushColor(hdc,RGB(R,G,B));
    	
    	Ellipse (hdc, 
    		ptCenter.x - radius, 
    		ptCenter.y + radius,
    		ptCenter.x + radius,
    		ptCenter.y - radius);
    }
    
    // the simplest way to draw a circle:
    void ReallySimpleCircle (HDC hdc, LONG radius, POINT ptCenter, COLORREF crColor)
    {
    	LONG	cx = 0, cy;
    	double	xLimit = sqrt ((double) (radius * radius) / 2);
    
    	while (cx++ <= xLimit)
    	{
    		cy = (LONG) floor (sqrt ((double) radius * radius - cx * cx));
    		SetPixel (hdc, cx + ptCenter.x, cy + ptCenter.y, crColor);		// 45-90	degrees
    		SetPixel (hdc, cx + ptCenter.x, -cy + ptCenter.y, crColor);		// 270-315	degrees
    		SetPixel (hdc, -cx + ptCenter.x, cy + ptCenter.y, crColor);		// 90-135	degrees
    		SetPixel (hdc, -cx + ptCenter.x, -cy + ptCenter.y, crColor);	// 225-270	degrees
    		SetPixel (hdc, cy + ptCenter.x, cx + ptCenter.y, crColor);		// 0-45		degrees
    		SetPixel (hdc, cy + ptCenter.x, -cx + ptCenter.y, crColor);		// 315-360	degrees
    		SetPixel (hdc, -cy + ptCenter.x, cx + ptCenter.y, crColor);		// 135-180	degrees
    		SetPixel (hdc, -cy + ptCenter.x, -cx + ptCenter.y, crColor);	// 180-225	degrees
    	}
    }

  2. #2
    Registered User
    Join Date
    Dec 2007
    Posts
    214
    Make these changes : In WndProcedure :

    change this HDC hdc = GetDC(hWnd); to HDC hdc;

    Add this : PAINTSTRUCT ps;

    change WM_PAINT handler to this :

    Code:
    case WM_PAINT:
    	{	
                  	hdc = BeginPaint(hWnd, &ps);
    
    		//DrawRectangle(hWnd);
    		//ReallySimpleCircle (hdc, 50, ptCenter, REALLYSIMPLE_CIRCLE_COLOR);
    		Win32APIGDICircle (hdc, 200, ptCenter, 0, 255, 128);
                    
                    EndPaint(hWnd, &ps);
    		break;
    	}

  3. #3
    Registered User
    Join Date
    Apr 2008
    Posts
    610
    Quote Originally Posted by DaveH View Post
    Make these changes : In WndProcedure :

    change this HDC hdc = GetDC(hWnd); to HDC hdc;

    Add this : PAINTSTRUCT ps;

    change WM_PAINT handler to this :

    Code:
    case WM_PAINT:
    	{	
                  	hdc = BeginPaint(hWnd, &ps);
    
    		//DrawRectangle(hWnd);
    		//ReallySimpleCircle (hdc, 50, ptCenter, REALLYSIMPLE_CIRCLE_COLOR);
    		Win32APIGDICircle (hdc, 200, ptCenter, 0, 255, 128);
                    
                    EndPaint(hWnd, &ps);
    		break;
    	}
    works like a charm... Thanx a lot, so it's best to use BeginPaint to get a DC of a window?

  4. #4
    Registered User
    Join Date
    Dec 2007
    Posts
    214
    Quote Originally Posted by csonx_p View Post
    works like a charm... Thanx a lot, so it's best to use BeginPaint to get a DC of a window?
    Only within a WM_PAINT message.

  5. #5
    train spotter
    Join Date
    Aug 2001
    Location
    near a computer
    Posts
    3,868
    SelectObject (hdc, GetStockObject (DC_BRUSH));

    In .NET era IDEs GDI objects are cleaned up, so this line may not be causing a leak but...

    Although you do not have to delete a stock GDI object, you should always replace default GDI objects in the HDC before trying to clean it up (done by EndPaint() in this case).


    Code:
    HBRUSH hOrigBrush=SelectObject (hdc, GetStockObject (DC_BRUSH));
    //use
    SelectObject (hdc, hOrigBrush);
    "Man alone suffers so excruciatingly in the world that he was compelled to invent laughter."
    Friedrich Nietzsche

    "I spent a lot of my money on booze, birds and fast cars......the rest I squandered."
    George Best

    "If you are going through hell....keep going."
    Winston Churchill

  6. #6
    Algorithm Dissector iMalc's Avatar
    Join Date
    Dec 2005
    Location
    New Zealand
    Posts
    6,318
    Quote Originally Posted by csonx_p View Post
    works like a charm... Thanx a lot, so it's best to use BeginPaint to get a DC of a window?
    What was happening is that without BeginPaint/EndPaint Windows doesn't actually know that you've completed the redrawing of the window, and so it immediately posts another WM_PAINT message to try again. It's this flood of WM_PAINT messages thousands of times per second that caused everything to slow down.

    btw, Never use ValidateRect or other validation functions instead of BeginPaint/EndPaint either. That does cause problems.
    My homepage
    Advice: Take only as directed - If symptoms persist, please see your debugger

    Linus Torvalds: "But it clearly is the only right way. The fact that everybody else does it some other way only means that they are wrong"

  7. #7
    Registered User
    Join Date
    Apr 2008
    Posts
    610
    Quote Originally Posted by iMalc View Post
    What was happening is that without BeginPaint/EndPaint Windows doesn't actually know that you've completed the redrawing of the window, and so it immediately posts another WM_PAINT message to try again. It's this flood of WM_PAINT messages thousands of times per second that caused everything to slow down.

    btw, Never use ValidateRect or other validation functions instead of BeginPaint/EndPaint either. That does cause problems.
    cool info, thanx

  8. #8
    Registered User
    Join Date
    Apr 2008
    Posts
    610
    This is my updated code!

    Code:
    case WM_PAINT:
    			{		
    				//ZeroMemory((void *)ps,sizeof(PAINTSTRUCT));
    				hdc = BeginPaint(hWnd, &ps);
    
    				Win32APIGDICircle (hdc, radius, ptCenter, 0, 255, 128);
    				Win32APIGDICircle (hdc, radius-50, ptCenter, 128, 255, 128);
    				Win32APIGDICircle (hdc, radius-100, ptCenter, 255, 255, 255);
    
    				// draw and rotate the line
    				for(static int x=0;x<180;x++)
    				{
    					POINT coord = SetPOINT(ptCenter, radius);
    
    					pen = CreatePen(PS_SOLID, 2, RGB(128, 255, 128));	
    					oldPen = (HPEN)SelectObject(hdc, pen);				
    
    					MoveToEx(hdc, ptCenter.x,ptCenter.y, NULL);		
    					LineTo(hdc, coord.x, coord.y);
    
    					Sleep(50);	// 2 secs for every rotations
    				}
    
    				SelectObject(hdc, oldPen); 				
    				DeleteObject(pen);
    				EndPaint(hWnd, &ps);
    
    				break;
    How do i erase a previous line drawn? At the moment many lines are drawn forming a complete circle...

  9. #9
    Registered User
    Join Date
    Dec 2007
    Posts
    214
    To erase the previous line you have to either overdraw the previous line or completely redraw your background each paint message.

    Also, I wouldn't use Sleep within the WM_PAINT message handler. Thats just slowing down your display. A better way might be to use a timer and each time the timer goes off send a paint message to draw the line. You'd need global variables to know the location of the line. Update them in the timer message handler and call paint.

  10. #10
    Registered User
    Join Date
    Apr 2008
    Posts
    610
    Quote Originally Posted by DaveH View Post
    To erase the previous line you have to either overdraw the previous line or completely redraw your background each paint message.

    Also, I wouldn't use Sleep within the WM_PAINT message handler. Thats just slowing down your display. A better way might be to use a timer and each time the timer goes off send a paint message to draw the line. You'd need global variables to know the location of the line. Update them in the timer message handler and call paint.

    Seems i'm getting somewhere, here's my progress code using timers... Only problem is the circle and the line flickers.. But i finally got the rotation! How do i avoid flickering?


    Code:
    POINT SetPOINT(LONG radius);
    long ErrorHandler(char errorMessage[]);
    void Win32APIGDICircle (HDC hdc, LONG radius, int R, int G, int B);
    LRESULT CALLBACK WndProcedure(HWND hWnd, UINT uMsg,WPARAM wParam, LPARAM lParam);
    
    // Globals
    int		angle=0;
    UINT_PTR	uResult;
    POINT		coord, ptCenter = {450,300};
    
    
    //---------------------------------------------------------------------------
    INT WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow)
    {
    	MSG        Msg;
    	HWND       hWnd;
    	WNDCLASSEX WndClsEx;
    
    	// Create the application window
    	WndClsEx.cbSize        = sizeof(WNDCLASSEX);
    	WndClsEx.style         = CS_HREDRAW | CS_VREDRAW;
    	WndClsEx.lpfnWndProc   = WndProcedure;
    	WndClsEx.cbClsExtra    = 0;
    	WndClsEx.cbWndExtra    = 0;
    	WndClsEx.hIcon		   = LoadIcon(hInstance, MAKEINTRESOURCE(400)); 
    	WndClsEx.hCursor	   = LoadCursor(hInstance, MAKEINTRESOURCE(200)); 
    	WndClsEx.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH);
    	WndClsEx.lpszMenuName  = NULL;
    	WndClsEx.lpszClassName = ClsName;
    	WndClsEx.hInstance     = hInstance;
    	WndClsEx.hIconSm       = LoadIcon(NULL, IDI_APPLICATION);
    
    	// Register the application
    	RegisterClassEx(&WndClsEx);
    
    	// Create the window object
    	hWnd = CreateWindowEx(0,
    		ClsName,
    		WndName,
    		WS_OVERLAPPEDWINDOW,
    		CW_USEDEFAULT,
    		CW_USEDEFAULT,
    		CW_USEDEFAULT,
    		CW_USEDEFAULT,
    		NULL,
    		NULL,
    		hInstance,
    		NULL);
    
    
    	if( !hWnd ) 
    		return FALSE; 
    
    	ShowWindow(hWnd, nCmdShow);
    	UpdateWindow(hWnd);
    
    	while( GetMessage(&Msg, NULL, 0, 0) )
    	{
    		TranslateMessage(&Msg);
    		DispatchMessage(&Msg);
    	}
    
    	return Msg.wParam;
    }
    
    //---------------------------------------------------------------------------
    LRESULT CALLBACK WndProcedure(HWND hWnd, UINT Msg,
                                   WPARAM wParam, LPARAM lParam)
    {
    	PAINTSTRUCT ps;
    	HPEN pen, oldPen;
    	HDC hdc;
    	long radius=150;
    
    	double	xLimit = sqrt ((double) (radius * radius) / 2);
    
    	switch(Msg)
    	{
    	case WM_CREATE:
    
    		// Set the timer 
    		uResult = SetTimer(hWnd, IDT_ROTATER, 10,(TIMERPROC) NULL); 
    
    		break;
    
    	case WM_PAINT:
    		{		
    			ZeroMemory(&ps,sizeof(PAINTSTRUCT));
    			hdc = BeginPaint(hWnd, &ps);
    
                            // Draw a circle
    			Win32APIGDICircle (hdc, radius, 0, 255, 128);
    			
    			// Create pen
    			pen = CreatePen(PS_SOLID, 2, RGB(128, 255, 128));	
    			oldPen = (HPEN)SelectObject(hdc, pen);		
    
    			// Draw line
    			SetPOINT(radius);
    			MoveToEx(hdc, ptCenter.x,ptCenter.y, NULL);		
    			LineTo(hdc, coord.x, coord.y);
    
    			// Delete & Release DCs
    			SelectObject(hdc, oldPen); 				
    			DeleteObject(pen);
    			DeleteDC(hdc);
    			EndPaint(hWnd, &ps);
    
    		}
    
    		break; 
    
    	case WM_TIMER: 
    		angle-=2;	// change angle (rotate) 2 degrees apart
    		Sleep(2);	
    
    	        /* Call the WM_PAINT */
    		InvalidateRect (hWnd, NULL, TRUE);
    		UpdateWindow(hWnd);
    
    		break;
    
    	case WM_DESTROY:
    		KillTimer(hWnd, IDT_ROTATER); 
    		PostQuitMessage(WM_QUIT);
    
    		break;
    
    	default:
    		// Process the left-over messages
    		return DefWindowProc(hWnd, Msg, wParam, lParam);
    	}
    	// If something was not done, let it go
    	return 0;
    }
    
    // Win32API GDI circle:
    void Win32APIGDICircle (HDC hdc, LONG radius,int R, int G, int B)
    {
    	SelectObject (hdc, GetStockObject (DC_BRUSH));
    	SetDCBrushColor(hdc,RGB(R,G,B));
    
    	Ellipse (hdc, 
    		ptCenter.x - radius, 
    		ptCenter.y + radius,
    		ptCenter.x + radius,
    		ptCenter.y - radius);
    }
    
    /* Calculate the line points */
    POINT SetPOINT(LONG radius)
    {
    	const float Deg2Rad = 0.017453292;
    	float degInRad;
    
    	degInRad = angle*Deg2Rad;   // Convert degrees to radians
    
    	// Finds the adjacent value
            coord.x = (long)(ptCenter.x + (cos(degInRad)*(float)radius));	
    
            // Finds the hypotenuse value
    	coord.y = (long)(ptCenter.y - (sin(degInRad)*(float)radius));	
    
    	return coord;
    }
    Last edited by csonx_p; 04-24-2008 at 01:48 AM.

  11. #11
    Registered User
    Join Date
    Dec 2007
    Posts
    214
    To avoid the flickering you need to use memory device contexts. Basically you create a compatible memory dc and draw to that. Then to display you bitblt to the paint dc. Also called double buffering. Search for memory dc or double buffering and you should find examples.

  12. #12
    Registered User
    Join Date
    Apr 2008
    Posts
    610
    Quote Originally Posted by DaveH View Post
    To avoid the flickering you need to use memory device contexts. Basically you create a compatible memory dc and draw to that. Then to display you bitblt to the paint dc. Also called double buffering. Search for memory dc or double buffering and you should find examples.
    Hi dave, i thought i was doing that here...

    Code:
    	case WM_PAINT:
    		{		
    			ZeroMemory(&ps,sizeof(PAINTSTRUCT));
    			hdc = BeginPaint(hWnd, &ps);
    
                            // Draw a circle
    			Win32APIGDICircle (hdc, radius, 0, 255, 128);
    			
    			// Create pen
    			pen = CreatePen(PS_SOLID, 2, RGB(128, 255, 128));	
    			oldPen = (HPEN)SelectObject(hdc, pen);		
    
    			// Draw line
    			SetPOINT(radius);
    			MoveToEx(hdc, ptCenter.x,ptCenter.y, NULL);		
    			LineTo(hdc, coord.x, coord.y);
    
    			// Delete & Release DCs
    			SelectObject(hdc, oldPen); 				
    			DeleteObject(pen);
    			DeleteDC(hdc);
    			EndPaint(hWnd, &ps);
    
    		}
    perhaps i should now use BitBlt as well, but at which stage? searching for info may not help since there's a lot out there!

  13. #13
    Banned master5001's Avatar
    Join Date
    Aug 2001
    Location
    Visalia, CA, USA
    Posts
    3,685
    Basically you are going to read one of those examples then implement it by creating a memory HDC then drawing your image to that memory HDC then using BitBlt() to copy the memory HDC to the screen device context. When would you do such a thing? When you are done drawing everything to memory and prior to calling EndPaint().

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. WM_CAPTION causing CreateWindowEx() to fail.
    By Necrofear in forum Windows Programming
    Replies: 8
    Last Post: 04-06-2007, 08:23 AM
  2. 6 measly errors
    By beene in forum Game Programming
    Replies: 11
    Last Post: 11-14-2006, 11:06 AM
  3. Linking OpenGL in Dev-C++
    By linkofazeroth in forum Game Programming
    Replies: 4
    Last Post: 09-13-2005, 10:17 AM
  4. My Window Class
    By Epo in forum Game Programming
    Replies: 2
    Last Post: 07-10-2005, 02:33 PM
  5. OpenGL Window
    By Morgul in forum Game Programming
    Replies: 1
    Last Post: 05-15-2005, 12:34 PM