/*/=================================================================================
1. 버튼 , 메뉴, 스크롤 등 결국 윈도우이다
2. 자식은 부모에게 통보를 한다. WM_COMMAND(통신코드)(버튼클릭같은)
3. 부모는 자식에게 메시지를 보낸다.(형태변환같은)
4. 자식은 자신이 그려지기 전에 부모에게 컨트롤 권한을 넘긴다. (WM_CTLxxxxxxx);
5. 부모는 자식이 보내준 권한을 가지고 자식이 그려질 형태를 수정한다.
//=================================================================================*/
//자식(버튼)이 부모에게 WM_COMMAND를 보낼때 사용할 통지코드(메시지를 보내는 이유)
#define BIN_LCLICK 1
#define BIN_RCLICK 2
#define BIN_LDBCLICK 3
#define BIN_RDBCLICK 4
//부모가 자식(버튼)을 만들어 놓고 자식에게 보낼 수 있는 메시지를 설계한다.
//부모 - 자식 간의 약속
#define BM_CHANGESTYLE WM_USER + 10
#define BM_CHANGETHICK WM_USER + 11
#include<windows.h>
LRESULT CALLBACK WndProc(HWND hwnd,UINT iMessage,WPARAM wParam,LPARAM lParam);
LRESULT CALLBACK ChildWndProc(HWND hwnd,UINT iMessage,WPARAM wParam,LPARAM lParam);
HINSTANCE g_inst;
void Draw3dRect(HDC hdc, int x, int y, int xx, int yy,
BOOL down, int width )
{
COLORREF clrMain = RGB(192,192,192),
clrLight = RGB(255,255,255),
clrDark = RGB(128,128,128);
HPEN hPen1, hPen2, hOldPen;
HBRUSH hBrush, hOldBrush;
if(down)
{
hPen2 = CreatePen(PS_SOLID,1,clrLight);
hPen1 = CreatePen(PS_SOLID,1,clrDark);
}
else
{
hPen1 = CreatePen(PS_SOLID,1,clrLight);
hPen2 = CreatePen(PS_SOLID,1,clrDark);
}
hBrush = CreateSolidBrush( clrMain );
hOldPen = (HPEN)SelectObject(hdc, hPen1);
hOldBrush = (HBRUSH)SelectObject(hdc, hBrush);
Rectangle(hdc, x , y, xx+1, yy+1);
for(int i=0; i < width; i++)
{
SelectObject(hdc, hPen1);
MoveToEx(hdc, xx - 1, y, 0 );
LineTo(hdc, x, y);
LineTo(hdc, x, yy - 1 );
SelectObject(hdc, hPen2);
MoveToEx(hdc, x, yy,0);
LineTo(hdc, xx, yy);
LineTo(hdc, xx, y);
x++; y++; xx--; yy--;
}
SelectObject(hdc, hOldPen);
SelectObject(hdc, hOldBrush);
DeleteObject(hPen1);
DeleteObject(hPen2);
DeleteObject(hBrush);
}
int WINAPI WinMain(HINSTANCE hInstance,
HINSTANCE hPrev,
LPSTR lpCmdLine,
int nShowCmd)
{
ATOM atom;
g_inst=hInstance;
MSG Message;
//1. 위도우 클래스 만들기 (10가지를 다 정확히 입력하지 않으면 화면이 뜨지 않는다.)
WNDCLASS wc; //미리정의된 10개 항목을 채우는 클래스 (WNDCLASSEX 12개 항목 10개 항목에 작은 아이콘, 구조체 크기를 포함한다.)
wc.cbClsExtra = 0;
wc.cbWndExtra = 0;
wc.hbrBackground = (HBRUSH)GetStockObject( WHITE_BRUSH);
wc.hCursor = LoadCursor ( 0, IDC_CROSS);
wc.hIcon = LoadIcon ( 0, IDI_WINLOGO );
wc.hInstance = hInstance;
wc.lpfnWndProc = WndProc;
wc.lpszClassName= "First";
wc.lpszMenuName = 0;
wc.style = 0;
//2. 윈도우 클래스 등록하기.
atom = RegisterClass( & wc ); // 등록을 하는 함수도 2가지가 있다. RegisterClass와 RegisterClassEx가 있다.
wc.lpfnWndProc = ChildWndProc;
wc.lpszClassName = "CHILD";
RegisterClass( & wc );
//WNDCLASS로 만들었으면 RegisterClass로 등록하고 WNDCLASSEX로 만들었으면 RegisterClassEx로 등록
//3. 등록된 클래스를 사용해서 윈도우 만들기.
// typedef long HWND; // 윈도우의 번호를 담을때 사용
HWND hwnd = CreateWindowEx(WS_EX_RIGHT , // 확장 윈도우 스타일
"First", // 윈도우 클래스 이름
"안녕", // 창이름
WS_OVERLAPPEDWINDOW, // 기본 Window Styles : & ~ 연산으로 기존스타일 제거하기
// WS_OVERLAPPEDWINDOW & ~WS_MAXIMIZEBOX
CW_USEDEFAULT, 0, CW_USEDEFAULT, 0, // X,Y,W,H
0, // 부모 윈도우 핸들( 번호 )
0, // 메뉴 핸들( 번호 )
hInstance, // 인스턴스 핸들
0); // 생성인자.( MDI 만들때 사용 )
//
//CreateWindowEx는 CreateWindow가 가지는 11개에 확장 윈도우 스타일 1가지 인자를 더 가져서 12가지 인자를 가진다.
//4. 윈도우 보여주기
ShowWindow(hwnd, nShowCmd);
while(GetMessage(&Message,0,0,0)) //메시지 큐에 가서 메시지를 꺼내오고 가져온 메시지를 윈도우 클래스에 등록된 메세지 처리함수로 전달한다.
{
TranslateMessage(&Message);
DispatchMessage(&Message);//가져온 메시지를 윈도우 클래스에 등록된 메시지 처리함수로 전달한다.
}
return 0;
}
LRESULT CALLBACK WndProc(HWND hwnd,UINT iMessage,WPARAM wParam,LPARAM lParam)
{
static HWND hChild;
switch(iMessage){
//자식이 자신을 그리기 전에 보내는 메시지 - 부모에게 ㅈ색을 변경할 기회를 준다. ※중요
case WM_CTLCOLORBTN:
{
HDC hdc = (HDC)wParam;
HWND h = (HWND)lParam;
if(hChild == h)//자식이 2개 이상이라면 내가 원하는 자식인지 확인
{
SetTextColor(hdc,RGB(200,0,200));
}
}
return 0;
case WM_DESTROY:
PostQuitMessage(0);
return 0 ;
case WM_CREATE:
hChild = CreateWindowEx(0 , // 확장 윈도우 스타일
"CHILD", // 윈도우 클래스 이름
"자식", // 창이름
WS_CHILD | WS_VISIBLE | WS_BORDER , // 기본 Window Styles : & ~ 연산으로 기존스타일 제거하기
// WS_OVERLAPPEDWINDOW & ~WS_MAXIMIZEBOX
0, 0, 100, 100, // X,Y,W,H
hwnd, // 부모 윈도우 핸들( 번호 )
(HMENU)1, // 메뉴 핸들( 번호 )
g_inst, // 인스턴스 핸들
0); // 생성인자.( MDI 만들때 사용 )
return 0;
case WM_COMMAND:
switch( LOWORD(wParam)) //자식 ID
{
case 1:
if(HIWORD(wParam) == BIN_LCLICK) // 통지코드 조사
{
MessageBox(hwnd,"Click!!","",MB_OK);
}
break;
}
return 0 ;
case WM_LBUTTONDOWN:
{
static int n= 2;
++n;
//자식에게 메시지를 보내서 두께를 변경하게 한다.
//wParam : 변경할 두께 , lParam : Not Use;
SendMessage(hChild,BM_CHANGETHICK,n,0);
}
return 0;
}
//꺼내온 메시지를 처리하지 않은경우 -> 바드시 아래 함수를 처리한다.
return(DefWindowProc(hwnd,iMessage,wParam,lParam));
}
LRESULT CALLBACK ChildWndProc(HWND hwnd,UINT iMessage,WPARAM wParam,LPARAM lParam)
{
static BOOL lDown = FALSE;
static int nThick = 2;
switch(iMessage){
case WM_LBUTTONDOWN:
lDown = TRUE; InvalidateRect(hwnd,0,FALSE);
SetCapture(hwnd);
return 0 ;
case BM_CHANGETHICK:
{
nThick = (int)wParam; //wParam에 두께를 보내기로 약속
InvalidateRect(hwnd,0,FALSE);
}
return 0;
case WM_LBUTTONUP:
{
if(GetCapture() == hwnd)
{
ReleaseCapture();
lDown = FALSE;
InvalidateRect(hwnd,0,FALSE);
}
//===================================================
//자식이 눌렸음을 부모에게 알려준다.
HWND hParent = GetParent(hwnd);
UINT id = GetDlgCtrlID(hwnd);
SendMessage(hParent, WM_COMMAND,
MAKELONG(id,BIN_LCLICK),
(LPARAM)hwnd);
}
return 0 ;
case WM_PAINT:
{
PAINTSTRUCT ps;
HDC hdc = BeginPaint(hwnd, &ps);
//자식은 hdc를 얻고 자신을 그리기 전에 부모에게 hdc 를 전달한다.
// 부모가 자식의 색상을 변경할 권한을 주기 위해서
// 이런 용도로 미리 만들어진 메시지가 WM_CTLCOLORxxx이다.
//wParam 에는 hdc를 lParam에는 자신의 핸들을 넣어 준다.
HWND hParent = GetParent(hwnd);
SendMessage(hParent, WM_CTLCOLORBTN,(WPARAM)hdc,(LPARAM)hwnd);
RECT rc;
GetClientRect(hwnd, &rc);
Draw3dRect(hdc, 0,0,rc.right, rc.bottom,lDown, nThick);
char s[256];
GetWindowText(hwnd, s, 256);
SetBkMode(hdc, TRANSPARENT);
if(lDown == TRUE)
{
OffsetRect(&rc,nThick,nThick);
}
DrawText(hdc,s,-1,&rc,DT_SINGLELINE | DT_CENTER | DT_VCENTER );
EndPaint(hwnd, &ps);
}
return 0;
}
//꺼내온 메시지를 처리하지 않은경우 -> 바드시 아래 함수를 처리한다.
return(DefWindowProc(hwnd,iMessage,wParam,lParam));
}