API-WM_NCHITTEST
- 프로그래밍/WindowsAPI
- 2011. 5. 31. 12:11
1. WM_NCHITTEST
현재 마우스 커서 위치가 윈도우의 어느 부분인지를 조사할 때 윈도우에게 WM_NCHITTEST 라는 메시지를 먼저 보낸다.
이 메시지의 wParam 은 사용되지 않으며 lParam에는 커서의 현재 좌표가 전달된다.
이 메시지를 보통 처리 하지않고 DefWindowProc 으로 전달하는데 이 함수는 lParam의 마우스 위치를 보고
윈도우의 어느 부분에 커서가 있는 조사해 다음 값 중 하나를 리턴한다.
[출처] [12장] 윈도우 관리 함수 8 - WM_NCHITTEST |작성자 어른아이
---------------------- DefwindowProc 의 리턴값 -------------------------------------
HTBORDER 크기 조절이 불가능한 경계선
HTBOTTOM 아래쪽 경계선
HTTOP 위쪽 경계선
HTBOTTOMLEFT 아래 왼쪽 경계선
HTBOTTOMRIGHT 아래 오른쪽 경계선
HTTOPLEFT 위 왼쪽 경계선
HTTOPRIGHT 위 오른쪽 경계선
HTLEFT 왼쪽 경계선
HTRIGHT 오른쪽 경계선
HTCAPTION 타이틀 바
HTCLIENT 작업영역
HTCLOSE 닫기 버튼
HTSIZE 크기 변경 박스
HTHELP 도움말 버튼
HTHCROLL 수평 스크롤 바
HTVSCROLL 수직 스크롤바
HTMENU 메뉴
HTMAXBUTTON 최대화 버튼
HTMINBUTTON 최소화 버튼
HTSYSMENU 시스템 네ㅠ
HTTRANSPARENT 같은 스레드의 다른 윈도우에 가려진 부분
--------------------------------------------------------------------------------------
이 리턴값을 도중에 가로채서 다른 값으로 바꾸면 다른 동작을 할수 있다고 한다
예를들어 캡션말고도 작업영역을 눌렀을때 캡션 처럼 이동이 가능한 윈도우를 만드려면 아래와 같이
case WM_NCHITTEST:
nHit = DefWindowProc(hWnd,iMessage,wParam,lParam);
if(nHit == HTCLIENT)
nHit = HTCAPTION;
return nHit;
이것 말고도 해당 메시지를 가로채서 다른 행동을 하게 할수 있는데
그 예제를 확인해보자
2. 예제
---------------------- WM_NCHITTEST 예제 ------------------
#include <windows.h>
LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);
HINSTANCE g_hInst;
LPCTSTR lpszClass = TEXT("First"); //윈도우 이름 및 타이틀바에 등록할 문자열
int APIENTRY WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpszCmdParam, int nCmdShow)
{
HWND hWnd;
MSG Message;
WNDCLASS WndClass;
g_hInst = hInstance;
//------------ 아래 부분은 윈도우 클래스를 설정해주는 것이다. --------------------
WndClass.cbClsExtra = 0;
WndClass.cbWndExtra = 0;
WndClass.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH);
WndClass.hCursor = LoadCursor(NULL,IDC_ARROW);
WndClass.hIcon = LoadIcon(NULL,IDI_APPLICATION);
WndClass.hInstance = hInstance;
WndClass.lpfnWndProc = WndProc;
WndClass.lpszClassName = lpszClass;
WndClass.lpszMenuName = NULL;
WndClass.style = CS_HREDRAW | CS_VREDRAW;
//------------ 위 부분은 윈도우 클래스를 설정해주는 것이다. --------------------
RegisterClass(&WndClass); // <-- 여기서는 위에서 설정한 클래스를 등록한다.
hWnd = CreateWindow(lpszClass,lpszClass,WS_OVERLAPPEDWINDOW,CW_USEDEFAULT,CW_USEDEFAULT,CW_USEDEFAULT,
CW_USEDEFAULT,NULL,(HMENU)NULL,hInstance,NULL); // 설정하고 등록한 윈도우를 생성한다.
ShowWindow(hWnd,nCmdShow); //생성한 윈도우를 출력..(이 함수를 호출하지않으면 윈도우가 보이지 않는다.)
while(GetMessage(&Message,NULL,0,0)) //사용자가 종료하기 전까지 반복해서 메세지 처리를 호출한다.
{
TranslateMessage(&Message);
DispatchMessage(&Message);
}
return (int)Message.wParam;
}
LRESULT CALLBACK WndProc(HWND hWnd, UINT iMessage, WPARAM wParam, LPARAM lParam) //여기서 실제로 메시지를 처리한다.
{
HDC hdc;
PAINTSTRUCT ps;
RECT crt;
int i;
int nHit;
POINT mpt;
TCHAR *Mes = TEXT("WM_NCHITTEST 메시지를 활용하는 예제입니다.");
switch(iMessage)
{
case WM_PAINT:
hdc = BeginPaint(hWnd,&ps);
GetClientRect(hWnd,&crt);
for(i=50; i>0; i-=5)
{
MoveToEx(hdc,crt.right,crt.bottom-i,NULL);
LineTo(hdc,crt.right-i,crt.bottom);
}
TextOut(hdc,10,10,Mes,lstrlen(Mes));
EndPaint(hWnd,&ps);
return 0;
case WM_NCHITTEST:
GetClientRect(hWnd,&crt);
mpt.x = LOWORD(lParam);
mpt.y = HIWORD(lParam);
ScreenToClient(hWnd,&mpt);
if(mpt.y > crt.bottom-50 && mpt.x > crt.right-50)
nHit = HTBOTTOMRIGHT;
else
{
nHit = DefWindowProc(hWnd,iMessage,wParam,lParam);
switch(nHit)
{
case HTCLIENT:
nHit = HTCAPTION;
break;
case HTLEFT:
nHit = HTMAXBUTTON;
break;
case HTMINBUTTON:
nHit=HTCLOSE;
break;
case HTMAXBUTTON:
nHit = HTMINBUTTON;
break;
case HTCLOSE:
nHit = HTLEFT;
break;
}
}
return nHit;
case WM_DESTROY:
PostQuitMessage(0);
return 0;
}
return DefWindowProc(hWnd,iMessage,wParam,lParam); //프로그래머가 처리하지 않은 나머지 동작을 기본처리로 넘긴다.
}
----------------------------------------------------------------------
작업영역의 크기를 조절할때 오른쪽 아래 버튼을 눌러서 조절할는데
크 영역이 좀 작은것 같을때 크기를 적당히 크게 해서 조절가능하게 하였다.
그거 말고도 닫기버튼 최대화 최소화 버튼을 다른메시지로 바껐는데
꼭 필요한 경우아니면 이런 작업은 안하는게 좋다고한다
- Cursor가 움직이거나 마우스 버튼을 누르거나 놓을 때, System은 커서 아래 있는 윈도우(마우스를 캡쳐한 경우 캡쳐한 윈도우)에게 WM_NCHITTEST 메시지를 보낸다.(sent)
- 이때 대부분 윈도우 프로시저는 이 메세지를 직접 처리 하지 않고 DefWindowProc으로 보내는데 DefWindowProc는 커서의 좌표를 조사해서 커서가 현재 윈도우의 어느 부분에 커서가 있는지 나타내는 Hit Test Code 를 리턴한다.
- WM_NCHITTEST의 결과로 얻어진 HitTestCode가 다음 메시지를 결정하는데 사용된다.
- 예제 코드( Control키를 누른 상태에서 클라이언트 영역에서 마우스의 왼쪽 버튼을 누르면 윈도우를 이동 )
// WM_NCHITTEST 를 처리하는 방법
case WM_NCHITTEST:
{
// 1. 먼저 DefWindowProc()으로 전달해서 hit test code를 얻는다.
int code = DefWindowProc( hwnd, msg, wParam, lParam );
// 2. code를 조작한다.
if( code == HTCLIENT && GetKeyState( VK_CONTROL ) < 0 )
code = HTCAPTION;
// 3. code를 리턴한다. - 다음 메세지는 이 리턴값에 의해 결정된다.
return code;
}
이 글을 공유하기