draw outside WM_PAINT

Started by
10 comments, last by DinGY 18 years, 3 months ago
Is it possible to draw text or line outside WM_PAINT message ? I try and it dosen't work, any suggestion ?
DinGY
Yesterday is history.Tomorrow is a mystery. Today is a gift"
Advertisement
Do you use GDI or GDI+?

atm I use GDI+ and can draw from any part of code, i must only supply windows handle, so it must work even with GDI

edit: Check your code, cause WM_PAINT redraws window client when its been moved, resized etc. , so when you draw from other place than its possible, that it is immediately overdrawn
-----"Master! Apprentice! Heartborne, 7th Seeker Warrior! Disciple! In me the Wishmaster..." Wishmaster - Nightwish
This is my code, is there anything wrong ?
why it won't show anything

#include <windows.h>HDC hDC;PAINTSTRUCT ps;int x=0, y=0;LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam){	switch(msg)	{		case WM_CREATE:			SetTimer(hwnd, 10, 50, NULL);			break;		case WM_PAINT:			break;		case WM_TIMER:			x++;			y++;			hDC = BeginPaint(hwnd, &ps);			TextOut(hDC, x, y, "Hello", 5);			EndPaint(hwnd, &ps);			break;		case WM_DESTROY:			PostQuitMessage(WM_QUIT);			break;		default:			return DefWindowProc(hwnd, msg, wParam, lParam);	}		return 0;}int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,				   LPSTR lpCmdLine, int nCmdShow){	WNDCLASSEX wc;	HWND hwnd;	MSG msg;		wc.cbSize = sizeof(WNDCLASSEX);	wc.cbClsExtra = 0;	wc.cbWndExtra = 0;	wc.lpfnWndProc = WndProc;	wc.lpszClassName = "Example";	wc.hInstance = hInstance;	wc.style = CS_HREDRAW | CS_VREDRAW;	wc.hCursor = LoadCursor(NULL, IDC_ARROW);	wc.hIcon = LoadIcon(NULL, IDI_APPLICATION);	wc.hIconSm = LoadIcon(NULL, IDI_APPLICATION);	wc.hbrBackground = (HBRUSH)(COLOR_WINDOW);	wc.lpszMenuName = NULL;	RegisterClassEx(&wc);	hwnd = CreateWindow("Example", "Window Example", WS_OVERLAPPEDWINDOW , 						CW_USEDEFAULT, CW_USEDEFAULT, 						300, 300, NULL, NULL, hInstance, NULL);	ShowWindow(hwnd, nCmdShow);	UpdateWindow(hwnd);	while (GetMessage(&msg, NULL, 0, 0))	{		TranslateMessage(&msg);		DispatchMessage(&msg);	}	return (int)msg.wParam;}
DinGY
Yesterday is history.Tomorrow is a mystery. Today is a gift"
Never use BeginPaint() outside of WM_PAINT unless you really know what you're doing. The problem is that you're retrieving a handle to an empty region. BeginPaint will only return a handle to a paintable region when it's called under WM_PAINT. Either insert InvalidateRect(hwnd, NULL, _TRUE_OR_FALSE); before the call to BeginPaint (not recommended but it should work), or retrieve a handle to the entire client area (region) to paint by calling GetDC(hwnd); or GetDCEx(hwnd); if you want to set the initial clipping region. instead. - edit -[don't forget to call ReleaseDC(hwnd, hdc);
before leaving WM_TIMER]


xeddiex
one..
Quote:Original post by invisal
Is it possible to draw text or line outside WM_PAINT message ? I try and it dosen't work, any suggestion ?


It would work if you have a way to redraw the the line , cause the window doesn't save the graphical data unless you save it yourself , thats why in games the render sub is called every frame , WM_PAINT happens every time the window moves,resizes when ever they need to redraw any part of the non-client area , so it draws your line too , a good way is to save every pixel in memory and redraw them every time the window recives WM_PAINT , some people would save every line coord but that can be a lot of over heads when lines are erased and others are drawn and if you try to draw circles and save thier coords too you would be working with vector graphics , so see what best suits you and work with that .

"Any intelligent fool can make things bigger, more complex, and more violent. It takes a touch of genius -- and a lot of courage -- to move in the opposite direction."
here it is working

#include &lt;windows.h&gt;HDC hDC;PAINTSTRUCT ps;int x=0, y=0;LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam){	switch(msg)	{		case WM_CREATE:			SetTimer(hwnd, 10, 50, NULL);			break;		case WM_PAINT:		hDC = BeginPaint(hwnd,&ps);		ValidateRect(hwnd,NULL);		EndPaint(hwnd,&ps);			break;		case WM_TIMER:			x++;			y++;		hDC =	GetWindowDC(hwnd);		TextOut(hDC, x, y, "Hello", 5);			break;		case WM_DESTROY:			PostQuitMessage(WM_QUIT);			break;		default:			return DefWindowProc(hwnd, msg, wParam, lParam);	}		return 0;}int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,				   LPSTR lpCmdLine, int nCmdShow){	WNDCLASSEX wc;	HWND hwnd;	MSG msg;		wc.cbSize = sizeof(WNDCLASSEX);	wc.cbClsExtra = 0;	wc.cbWndExtra = 0;	wc.lpfnWndProc = WndProc;	wc.lpszClassName = "Example";	wc.hInstance = hInstance;	wc.style = CS_HREDRAW | CS_VREDRAW;	wc.hCursor = LoadCursor(NULL, IDC_ARROW);	wc.hIcon = LoadIcon(NULL, IDI_APPLICATION);	wc.hIconSm = LoadIcon(NULL, IDI_APPLICATION);	wc.hbrBackground = (HBRUSH)(BLACK_BRUSH);	wc.lpszMenuName = NULL;	RegisterClassEx(&wc);	hwnd = CreateWindow("Example", "Window Example", WS_OVERLAPPEDWINDOW , 						CW_USEDEFAULT, CW_USEDEFAULT, 						300, 300, NULL, NULL, hInstance, NULL);	ShowWindow(hwnd, nCmdShow);	UpdateWindow(hwnd);	while (1)	{		if (GetMessage(&msg, NULL, 0, 0) != 0)		{		TranslateMessage(&msg);		DispatchMessage(&msg);		}		else		{			return 0;		}	}	return (int)msg.wParam;}



i tuned up some procedures for you hope you like it .
"Any intelligent fool can make things bigger, more complex, and more violent. It takes a touch of genius -- and a lot of courage -- to move in the opposite direction."
Quote:Original post by Code Fusion
here it is working

*** Source Snippet Removed ***


i tuned up some procedures for you hope you like it .


GetWindowDC is going to give him unwanted effects. He doesn't need a handle to the entire window if all he wants to do is paint in the client area and outside of WM_PAINT. Also, calling ValidateRect right before EndPaint is unnecessary since EndPaint does it for you.

xeddiex.
one..
GetWindowDC Get the handle to the Client+Non-Client area but i guess you would need both in a game and in case he wants to get only the client area he could use GetSystemMetrics to get the size of the two borders and add them to the obsloute value of the x,y this way he has the two options , and yes its not necessary to use ValidateRect cause BeginPaint does it automaticly but some Documention says its faster (no idea why).
"Any intelligent fool can make things bigger, more complex, and more violent. It takes a touch of genius -- and a lot of courage -- to move in the opposite direction."
Here, I fixed up CodeFusions code so it doesn't leave memory allocated (ReleaseDC added) and changed it to GetDC() (you can look up GetDCEx() if you like.

#include <windows.h>HDC hDC;PAINTSTRUCT ps;int x=0, y=0;LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam){	switch(msg)	{		case WM_CREATE:			SetTimer(hwnd, 10, 50, NULL);			break;		case WM_PAINT:		        hDC = BeginPaint(hwnd,&ps);                        // other draw code here.    		        EndPaint(hwnd,&ps);			break;		case WM_TIMER:			x++;			y++;		        hDC = GetDC(hwnd);		        TextOut(hDC, x, y, "Hello", 5);                        ReleaseDC(hDC);			break;		case WM_DESTROY:			PostQuitMessage(WM_QUIT);			break;		default:			return DefWindowProc(hwnd, msg, wParam, lParam);	}		return 0;}int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,				   LPSTR lpCmdLine, int nCmdShow){	WNDCLASSEX wc;	HWND hwnd;	MSG msg;		wc.cbSize = sizeof(WNDCLASSEX);	wc.cbClsExtra = 0;	wc.cbWndExtra = 0;	wc.lpfnWndProc = WndProc;	wc.lpszClassName = "Example";	wc.hInstance = hInstance;	wc.style = CS_HREDRAW | CS_VREDRAW;	wc.hCursor = LoadCursor(NULL, IDC_ARROW);	wc.hIcon = LoadIcon(NULL, IDI_APPLICATION);	wc.hIconSm = LoadIcon(NULL, IDI_APPLICATION);	wc.hbrBackground = (HBRUSH)(BLACK_BRUSH);	wc.lpszMenuName = NULL;	RegisterClassEx(&wc);	hwnd = CreateWindow("Example", "Window Example", WS_OVERLAPPEDWINDOW , 						CW_USEDEFAULT, CW_USEDEFAULT, 						300, 300, NULL, NULL, hInstance, NULL);	ShowWindow(hwnd, nCmdShow);	UpdateWindow(hwnd);	while (1)	{		if (GetMessage(&msg, NULL, 0, 0) != 0)		{		TranslateMessage(&msg); //Note: You only need this if you handle WM_CHAR or WM_SYSCHAR		DispatchMessage(&msg);		}		else		{			return 0;		}	}	return (int)msg.wParam;}


Hope that helps (and fixes the issue).

Edit:
GetWindowDC() -- Allows you to draw over the entire window.
GetDC() -- Only allows you to draw over the client area. Which in 90% of cases is what most people want to update. Not many people want to draw pixels over the title bar.
GetDCEx() -- Allows the same as GetDC except you can specify regions and set some flags.

For what you seem to be doing, I highly recommend GetDC(), it will make your life a lot easier, no worrying about offsets and stuff.

"Those who would give up essential liberty to purchase a little temporary safety deserve neither liberty nor safety." --Benjamin Franklin

now I get it, I should leave hDC = BeginPaint(hwnd, &ps); and EndPaint(hwnd,&ps); in WM_PAINT even you draw something outside WM_PAINT right.
DinGY
Yesterday is history.Tomorrow is a mystery. Today is a gift"

This topic is closed to new replies.

Advertisement