1. 메뉴 추가( 오너드로우 )
more..
// 특정 메뉴를 OWNERDRAW로 변경하고 ItemData에 색상을 넣어 준다.
void AddMenuColor( HMENU hMenu, UINT id, COLORREF color )
{
ModifyMenu( hMenu, id, MF_BYCOMMAND | MF_OWNERDRAW, id, "" );
// ItemData에 색상을 기록해 둔다.
MENUITEMINFO mi = { 0 };
mi.cbSize = sizeof(mi);
mi.dwItemData = (DWORD)color;
mi.fMask = MIIM_DATA;
SetMenuItemInfo( hMenu, id, FALSE, &mi ); // FALSE :2번째 인자가 ID라는 의미.TRUE:POSITION
}
LRESULT CALLBACK WndProc( HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
switch( msg )
{
case WM_CREATE:
{
// 그리기 메뉴 1단계 - 메뉴항목의 속성을 OWNERDRAW로 변경한다.
HMENU h1 = GetMenu( hwnd );
HMENU h2 = GetSubMenu( h1, 0 );
AddMenuColor( h2, ID_RED, RGB( 255, 0, 0 ) );
AddMenuColor( h2, ID_BLUE, RGB( 0, 0, 255 ) );
AddMenuColor( h2, ID_GREEN, RGB( 0, 255, 0 ) );
// ModifyMenu(
// h2, // 팝업메뉴 핸들
// ID_RED, // ID 또는 Position
// MF_BYCOMMAND | MF_OWNERDRAW,
// // 2번째 파라미터의 해석 방법 | 속성...
// // MF_BYCOMMAND(ID), MF_BYPOSITION(순서)
// ID_RED, // 변경할 ID
// "빨간색" // 변경할 Text
// );
}
return 0;
case WM_MEASUREITEM:
{
// 그리기 메뉴 2단계
// OS 가 구조체를 만들어서 포인터를 보내준다. 그 구조체에 크기를 채워준다.
LPMEASUREITEMSTRUCT p = (LPMEASUREITEMSTRUCT)lParam;
if( p->itemID == ID_RED || p->itemID == ID_BLUE || p->itemID == ID_GREEN )
// 메뉴 Item ID 조사
{
p->itemWidth = GetSystemMetrics( SM_CYMENU ) * 4;
p->itemHeight = GetSystemMetrics( SM_CYMENU );
}
}
return 0;
case WM_DRAWITEM:
{
// 그리기 메뉴 3단계 - Item 에 원하는 그림을 그린다.
LPDRAWITEMSTRUCT p = (LPDRAWITEMSTRUCT)lParam;
HDC hdc = p->hDC;
RECT rc = p->rcItem; // 그려야 하는 Item의 크기
int state = p->itemState; // Item의 상태
int id = p->itemID;
if( id == ID_RED || p->itemID == ID_BLUE || p->itemID == ID_GREEN )
{
RECT rcTemp = rc;
// 선택여부를 조사한다.
COLORREF c;
/////////////////////////////////////////////////////
if( state & ODS_SELECTED ) // 선택여부를 나타내는 필드
{
c = GetSysColor( COLOR_HIGHLIGHT );
InflateRect( &rcTemp, -2, -2 ); // 사각형을 줄인다.
}
else
{
c = GetSysColor( COLOR_MENU );
InflateRect( &rcTemp, -5, -5 ); // 사각형을 줄인다.
}
/////////////////////////////////////////////////////
HBRUSH hBrush1 = CreateSolidBrush( c );
FillRect( hdc, &rc, hBrush1 );
// ItemData에서 색상을 얻는다.
COLORREF color = (COLORREF)(p->itemData);
HBRUSH hBrush = CreateSolidBrush( color );
FillRect( hdc, &rcTemp, hBrush );
DeleteObject( hBrush1 );
DeleteObject( hBrush );
}
}
return 0;
case WM_RBUTTONUP:
return DefWindowProc( hwnd, msg, wParam, lParam ); // MSDN에서 강조함!!확인!
// ContextMenu 나타내기 - Tray에서 나타내려면 WM_RBUTTONUP을 사용해라.!
case WM_CONTEXTMENU:
{
// 1. 메뉴 Load
HMENU hMenu = LoadMenu( GetModuleHandle(0), MAKEINTRESOURCE(IDR_MENU1) );
// 2. 나타낼 팝업 메뉴 핸들 얻기
HMENU hSubMenu = GetSubMenu( hMenu, 0 );
// 3. 현재 커서의 위치에 나타낸다.
POINT pt;
GetCursorPos( &pt );
TrackPopupMenu(
hSubMenu, TPM_LEFTBUTTON | TPM_RIGHTBUTTON,
pt.x, pt.y, // 좌표
0, // Reserved(사용안함)
hwnd, // 메뉴 메세지를 받을 윈도우
0 ); // 사용안함.
// LoadIcon, LoadCursor는 Destroy 할 필요없다.
// LoadMenu 는 Destroy 해야 한다. --- MSDN 참고.
DestroyMenu( hMenu );
}
return 0;
case WM_DESTROY:
PostQuitMessage(0);
return 0;
}
return DefWindowProc( hwnd, msg, wParam, lParam);
}
2. 모달 다이얼로그 값 읽어오기
more..
// DialogBoxParam 을 사용하기 위해선 구조체가 필요하다.
// 각 컨트롤에서 값을 꺼내기 위해 사용한다.
typedef struct _DATA
{
int cx;
int cy;
}DLGDATA;
// DialogBox를 나타내려면 DialogProc가 있어야 한다.
BOOL CALLBACK DlgProc( HWND hDlg, UINT msg, WPARAM wParam, LPARAM lParam )
{
static DLGDATA* pData;
switch( msg )
{
case WM_INITDIALOG:
{
// 부모를 사용가능하게 한다.
pData = (DLGDATA*)lParam;
// 구조체 값으로 컨트롤을 초기화 한다.
SetDlgItemInt( hDlg, IDC_EDIT1, pData->cx, 0 );
SetDlgItemInt( hDlg, IDC_EDIT2, pData->cy, 0 );
// 부모를 사용가능하게 한다.
//EnableWindow( GetParent( hDlg ), TRUE );
}
return TRUE;
case WM_COMMAND:
switch( LOWORD(wParam) )
{
case IDOK:
{
// 값을 꺼내서 부모가 전달해 준 구조체에 넣는다.
BOOL bRet = 0;
pData->cx = GetDlgItemInt( hDlg, IDC_EDIT1, &bRet, 0 );
pData->cy = GetDlgItemInt( hDlg, IDC_EDIT2, &bRet, 0 );
/*
char buf[256];
// 결국 각 Control의 ID를 핸들로 변경하면 다양한 윈도우 관련 함수를 사용가능하다.
//HWND hEdit = GetDlgItem( hDlg, IDC_EDIT1 );
//GetWindowLong( hEdit, buf, 256 );
GetDlgItemText( hDlg, IDC_EDIT1, buf, 256 );
MessageBox( 0, buf, "", MB_OK );
*/
//////////////////////////////////////////////////////////////////////////
EndDialog( hDlg, IDOK ); // 모달 Dialog를 닫는다.
}
break;
case IDCANCEL: EndDialog( hDlg, IDCANCEL ); break;
}
return TRUE; // 메세지를 처리한 경우
}
return FALSE; // 메세지를 처리 하지 않은 경우
}
LRESULT CALLBACK WndProc( HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
static int sx, sy;
switch( msg )
{
RECT aa;
case WM_LBUTTONDOWN:
{
DialogBox( 0, 0, 0, 0 );
// 값을 꺼내오기 위해서 구조체 생성
DLGDATA data;
data.cx = sx;
data.cy = sy;
// 모달 Dialog 나타내기
UINT ret = DialogBoxParam(
GetModuleHandle( 0 ), // hInstance
MAKEINTRESOURCE( IDD_DIALOG1 ), // 리소스 ID
hwnd, // 부모 윈도우 핸들
(DLGPROC)DlgProc, // 메세지 함수
(LPARAM)&data // WM_INITDIALOG의 lParam으로 간다.
);
if ( ret == IDOK ) // EndDialog의 리턴값
{
// 구조체에서 값을 꺼내서 static 변수에 넣어 놓고 사용한다.
sx = data.cx;
sy = data.cy;
InvalidateRect( hwnd, 0, TRUE );
}
}
return 0;
case WM_PAINT:
{
PAINTSTRUCT ps;
HDC hdc = BeginPaint( hwnd, &ps );
TextOut( hdc, sx, sy, "hello", 5 );
EndPaint( hwnd, &ps );
}
return 0;
case WM_DESTROY:
PostQuitMessage(0);
return 0;
}
return DefWindowProc( hwnd, msg, wParam, lParam);
}
4. 메뉴적재
more..
// 메뉴를 적재하는 3가지 방법중 1번째
// 1. 윈도우 클래스에 메뉴 리소스 ID를 등록한다.
wc.lpszMenuName = IDR_MENU1;
// 메뉴를 붙이는 2번쨰 방법.
// 2. CreateWindowEx 9번째 인자를 사용한다.
hMenu = LoadMenu( hInstance, MAKEINTRESOURCE(IDR_MENU1) );
SetMenu( hwnd, hMenu );
// 3. 핸들을 얻어내서 추가하기
HMENU h1 = GetMenu( hwnd ); // 메뉴 바의 핸들을 얻는다.
HMENU h2 = GetSubMenu( h1, 0 ); // h1의 1번째 팝업 메뉴의 핸들을 얻는다.
MENUINFO mi = { 0 };
mi.cbSize = sizeof( mi );
mi.hbrBack = CreateSolidBrush( RGB( 0, 255, 0 ) );
mi.fMask = MIM_BACKGROUND;
// 팝업 메뉴를 관리하는 구조체를 변경한다.
SetMenuInfo( h2, &mi );
//AppendMenu( h2, MF_STRING, 50001, "추가메뉴" );
//// 메뉴 바에도 직접 추가 할 수 있다.
//AppendMenu( h1, MF_STRING, 50002, "AAA" );
/// 메뉴 바에 추가한 경우 즉시 그리게 한다.
//DrawMenuBar( hwnd );
5. 전체 화면 흉내내기
more..
if ( bFull == FALSE )
{
bFull = TRUE;
hMenu = GetMenu( hwnd ); // 메뉴 핸들을 보관하고
SetMenu( hwnd, 0 ); // 메뉴를 떼어낸다.
ModifyStyle( hwnd, WS_CAPTION, 0 );
ShowWindow( hwnd, SW_MAXIMIZE );
}
else
{
bFull = FALSE;
SetMenu( hwnd, hMenu );
hMenu = 0;
ModifyStyle( hwnd, 0, WS_CAPTION );
ShowWindow( hwnd, SW_SHOWNORMAL );
}
6. 모달리스 ( 메시지 루프에서 다이얼로그 메시지 받기 )
more..
while ( GetMessage( &msg, 0, 0, 0) )
{
// 모달리스는 자체 루프를 가지고 있지 않다.
// 그래서... IsDialogMessage()를 직접 호출해야 한다.
if ( !IsWindow( g_hDlg ) || !IsDialogMessage( g_hDlg, &msg ))
{
TranslateMessage( &msg );
DispatchMessage( &msg );
}
}
// DialogBox를 나타내려면 DialogProc가 있어야 한다.
BOOL CALLBACK DlgProc( HWND hDlg, UINT msg, WPARAM wParam, LPARAM lParam )
{
static DLGDATA* pData;
switch( msg )
{
case WM_INITDIALOG:
{
// 부모를 사용가능하게 한다.
pData = (DLGDATA*)lParam;
// 구조체 값으로 컨트롤을 초기화 한다.
SetDlgItemInt( hDlg, IDC_EDIT1, pData->cx, 0 );
SetDlgItemInt( hDlg, IDC_EDIT2, pData->cy, 0 );
// 부모를 사용가능하게 한다.
//EnableWindow( GetParent( hDlg ), TRUE );
}
return TRUE;
case WM_COMMAND:
switch( LOWORD(wParam) )
{
case IDOK:
{
// 값을 꺼내서 부모가 전달해 준 구조체에 넣는다.
BOOL bRet = 0;
pData->cx = GetDlgItemInt( hDlg, IDC_EDIT1, &bRet, 0 );
pData->cy = GetDlgItemInt( hDlg, IDC_EDIT2, &bRet, 0 );
// Data를 꺼내서 구조체에 넣어두고, 부모에게 메세지를 보내서 즉시 update 한다.
SendMessage( GetParent(hDlg), WM_USER+100, 0, 0 );
}
break;
case IDCANCEL:
DestroyWindow( hDlg );
g_hDlg = 0; // 그래야 다음번 모달리스 Dialog가 나타난다.
break;
}
return TRUE; // 메세지를 처리한 경우
}
return FALSE; // 메세지를 처리 하지 않은 경우
}
LRESULT CALLBACK WndProc( HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
static int sx, sy;
// 값을 꺼내오기 위해서 구조체 생성
static DLGDATA data;
switch( msg )
{
case WM_USER+100:
sx = data.cx;
sy = data.cy;
InvalidateRect( hwnd, 0, TRUE );
return 0;
case WM_LBUTTONDOWN:
{
if ( g_hDlg == 0 )
{
data.cx = sx;
data.cy = sy;
// 모달리스 Dialog 나타내기
g_hDlg = CreateDialogParam(
GetModuleHandle( 0 ), // hInstance
MAKEINTRESOURCE( IDD_DIALOG1 ), // 리소스 ID
hwnd, // 부모 윈도우 핸들
(DLGPROC)DlgProc, // 메세지 함수
(LPARAM)&data // WM_INITDIALOG의 lParam으로 간다.
);
ShowWindow( g_hDlg, SW_SHOW );
}
else
{
// Focus를 이동해서 사용자에게 알려준다.
SetFocus( g_hDlg );
}
}
return 0;
case WM_PAINT:
{
PAINTSTRUCT ps;
HDC hdc = BeginPaint( hwnd, &ps );
TextOut( hdc, sx, sy, "hello", 5 );
EndPaint( hwnd, &ps );
}
return 0;
case WM_DESTROY:
PostQuitMessage(0);
return 0;
}
return DefWindowProc( hwnd, msg, wParam, lParam);
}