리소스 편집기
리소스: 프로그램이 사용하는 데이터를 정수 값으로 변환해서 연결시켜 두고 이를 사용할 수 있도록 해주는 개념입니다.
이 개념이 없다면 외부 자원을 이용할 때 항상 경로를 직접 입력해서 연결을 해야 할 것입니다.
리소스 스크립트 파일(rc)에 기술됨
리소스의 종류
리소스 |
설명 |
아이콘 |
프로그램을 상징하는 이미지 |
커서 |
마우스 포인터 이미지 |
비트맵 |
그림 |
문자열 |
문자열 |
버전 |
프로그램 정보 |
메뉴 |
텍스트 명령 |
단축키 |
키보드 명령 |
도구모음 |
텍스트 명령 |
다이얼로그 |
대화상자 |
리소스 파일의 추가는 솔루션 탐색기의 리소스 파일 폴더를 선택하고 마우스 오른쪽 버튼을 눌러서 [추가] – [새 항목] – [리소스 파일]을 이용해서 추가가 가능합니다.
솔루션 탐색기의 아래쪽에 리소스 뷰 라는 탭이 있으며 이 탭을 눌러 나타나는 페이지에서 리소스를 관리하고 편집합니다.
리소스를 사용하기 위해서는 리소스를 작성하고 cpp 파일에 resource.h 파일을 인클루드 시켜야 합니다.
1. ICON
아이콘은 프로그램을 상징하는 이미지입니다.
아이콘을 리소스에 삽입하고 사용하는 프로젝트를 작성하겠습니다.
1) API 기본 창을 만드는 소스를 복사합니다.
기존 프로젝트도 관계 없습니다.
2) 솔루션 탐색기의 리소스 파일 폴더를 선택하고 마우스 오른쪽 버튼을 눌러서 추가가 가능합니다.
3) 리소스 뷰로 이동해서 리소스 파일을 선택하고 마우스 오른쪽 버튼을 클릭해서 [리소스 추가] 메뉴를 클릭해서 ICON을 클릭합니다.
기본적으로 IDI_ICON1이라는 ID로 생성될 것입니다.
ID는 프로그램에서 구별하는 이름이며 실제로는 정수 값입니다.
ID나 속성은 리소스를 선택하고 마우스 오른쪽 버튼을 클릭해서 [속성]로 가면 확인이 가능합니다.
4) 속성 탭에서 모양이 32 * 32 인 것을 확인하고 아이콘을 그립니다.
5) [이미지] 메뉴를 눌러서 16 * 16 아이콘을 선택하고 아이콘을 그립니다.
6) WinMain 함수에서 wndclass.hIcon=LoadIcon(NULL, IDI_APPLICATION); 부분을 아래와 같이 수정합니다.
wndclass.hIcon=LoadIcon(hInstance, MAKEINTRESOURCE(IDI_ICON1));
MAKEINTRESOURCE는 숫자로 정의된 리소스 이름을 문자열 형태로 바꿔주는 매크로
MS-WINDOWS가 제공하는 아이콘이나 커서를 사용할 때는 LoadIcon의 첫 번째 매개변수를 NULL을 주면 되지만 사용자가 추가한 리소스를 추가할 때는 어떤 인스턴스에 속한 리소스 인지를 밝혀 주어야 하므로 인스턴스 핸들을 입력해야 합니다.
7) resource.h 파일을 소스에 인클루드 합니다.
그리고 실행 후 보면 제목표시줄 좌측에 16 * 16으로 그린 아이콘이 표시가 될 것이고 Debug 폴더에 가서 exe 파일을 보면 32 * 32로 그린 아이콘이 화면에 보일 것입니다.
아이콘의 핸들 얻기
- 아이콘 핸들의 자료형: HICON
- 아이콘의 핸들 얻기
아이콘 ID에 해당하는 핸들을 얻기: LoadIcon(인스턴스 핸들, MAKEINTRESOURCE(아이콘ID))
현재 윈도우의 아이콘 핸들 얻기: (HICON)GetClassLong(윈도우 핸들, GCL_HICON)
실행 중 아이콘 변경하기
SetClassLong(윈도우 핸들, GCL_HICON, (LONG)아이콘핸들);
실행 중 아이콘 이미지를 화면에 출력하기
DrawIcon(DC핸들, x좌표, y좌표, 아이콘 핸들);
항상 32*32의 이미지가 그려짐
예제)
1. 윈도우 기본 프로젝트생성
2. 리소스 파일을 추가하고 리소스 추가를 이용해서 ICON 생성
3. WndProc 함수에서 인스턴스 핸들을 사용하기 위해 전역 영역에 변수 생성
HINSTANCE m_hInstance;
4. WinMain에서 hInstance를 m_hInstance에 대입
5. WndProc 작성
static HICON m_hIcon;
HDC hdc;
switch (message)
{
case WM_CREATE:
m_hIcon = LoadIcon(m_hInstance, MAKEINTRESOURCE(IDI_ICON1));
return 0;
case WM_RBUTTONDOWN:
hdc = GetDC(hwnd);
SetClassLong(hwnd, GCL_HICON,(LONG) m_hIcon);
DrawIcon(hdc, LOWORD(lParam), HIWORD(lParam), m_hIcon);
return 0;
case WM_DESTROY:
PostQuitMessage(0);
return 0;
}
2. CURSOR
커서는 마우스 포인터 모양입니다.
커서도 기본적으로 아이콘을 삽입하는 방법과 동일합니다.
자신이 작성한 CURSOR를 삽입하고자 하는 경우는
wndclass.hCursor=LoadCursor(hInstance, MAKEINTRESOURCE(커서ID));
외부 파일을 호출해서 아이콘을 적용시키고자 하는 경우는
LoadCursorFromFile(TEXT(“외부 커서파일의 위치 및 파일명”));
주의 하실 점은 C언어에서 경로명을 작성할 때 \는 제어문자를 나타내는 문자이므로 \\형태로 디렉토리를 나타낸다는 점입니다.
실행 중 커서 변경하기
SetClassLong(윈도우 핸들, GCL_HCURSOR, (LONG)커서핸들);
SetCursor(커서 핸들);
3. String Table
자주 사용하는 문자열을 테이블에 먼저 등록해두고 사용하는 것입니다.
문자열 변수가 있지만 문자열 리소스에 등록해두고 사용하면 문자열이 미리 파일에 등록되어 편리하게 사용할 수 있습니다.
리소스 탭에서 마우스 오른쪽을 클릭해서 [리소스 추가] – String Table을 선택하고 ID와 값 을 입력하면 됩니다.
ID를 만들고 이 ID가 표시할 문자열을 Caption에 작성합니다.
문자열 테이블의 리소스를 사용하려면 LoadString함수를 이용해서 사용합니다.
TCHAR title[256];
LoadString(hInstance, IDS_STRING, title, 256);
위와 같이 작성하면 IDS_STRING의 내용이 title 변수에 대입되게 됩니다.
4. BITMAP
BITMAP도 커서나 아이콘과 유사하게 사용됩니다.
비트맵은 배경화면으로 사용할 수 있게 되는데 먼저 바탕화면을 변경하는 방법을 알아보도록 하겠습니다.
CreateSolidBrush(RGB(R,G,B))는 RGB값으로 만들어진 브러시를 생성합니다.
CreateHatchBrush(int nIndex, COLORREF crColor)를 이용하면 nIndex에 해당하는 선을 만들고 crColor에 해당하는 선을 가진 브러시를 생성해 줍니다.
CreatePatternBrush(비트맵 이미지)는 비트맵 이미지로 만들어진 브러시를 생성합니다.
wndclass.hbrBackground = CreateSolidBrush(RGB(0,0,255));
위와 같이 변경하면 파란색으로 배경화면을 변경할 것입니다.
wndclass.hbrBackground = CreateHatchBrush(HS_CROSS,RGB(0,0,255));
위와 같이 변경하면 바둑판 모양의 파란색 선을 가진 배경을 만들어 줄 것입니다.
자신이 작성한 비트맵이나 import된 비트맵을 이용하는 경우
먼저 리소스 뷰 탭에서 비트맵을 Insert하고 비트맵을 작성해서 사용하는 것입니다.
wndclass.hbrBackground =
CreatePatternBrush (LoadBitmap (hInstance,MAKEINTRESOURCE(IDB_BITMAP1)));
5. 메뉴
메뉴는 사용자의 명령을 받아들이는 텍스트입니다.
메뉴를 작성하는 방법은 리소스 뷰에서 메뉴를 Insert 합니다.
그런 다음 추가된 메뉴를 더블 클릭해서 메뉴를 직접 추가하면 됩니다.
ID는 프로그램에서 구별해야 될 이름이므로 잘 작성해야 합니다.
Caption은 프로그램에서 보여질 텍스트 인데 & 표시 다음에 영문이 오면 ALT + &가 단축키가 됩니다.
\t를 이용하면 다음 문자열은 일정한 간격이 떨어진 상태에서 표시가 됩니다.
첫 글자에 밑줄이 그어집니다.
Pop-up에 체크가 되면 서브메뉴를 표시할 수 있는 메뉴가 됩니다.
Seperator는 구분 선을 만들어 줍니다.
Grayed 옵션을 선택하면 메뉴 항목은 비활성화 되어 텍스트는 회색이 되고 메시지를 발생시킬 수 없는 상태가 됩니다.
Enabled 속성이 False가 되면 누를 수 없는 상태가 됩니다.
메뉴를 만들고 메뉴를 사용할 수 있게 하려면 WinMain 함수의 wndclass.lpszMenuName = MAKEINTRESOURCE(메뉴 ID); 로 수정하면 됩니다.
하지만 이렇게 하면 메뉴가 보이기는 하지만 메뉴를 사용할 수는 없습니다.
메뉴를 실행시켜 주는 메시지는 WM_COMMAND 메시지입니다.
6. WM_COMMAND
프로그램 실행 중에 사용자가 메뉴 항목을 선택하면 WM_COMMAND 메시지가 발생합니다.
이때 어떤 메뉴 항목이 선택되었는가는 wParam의 하위 워드로 전달되므로
LOWORD(wParam)을 읽어 판단할 수 있습니다.
따라서 WndProc에서는 WM_COMMAND 메시지를 받을 경우 switch문이나 if 문으로 LOWORD(wParam)의 값에 따라 분기를 하여 각 메뉴 항목에 따른 처리를 수행해야 합니다. WM_COMMAND 메시지는 메뉴 항목을 선택할 때뿐 만 아니라 액셀러레이터(단축키)를 누를 때도 발생하며 또한 버튼, 텍스트 박스 등을 클릭해도 발생합니다.
부가정보
값 |
설명 |
lParam |
메시지를 발생시킨 컨트롤의 윈도우 핸들 |
LOWORD(wParam) |
메뉴나 액셀러레이터, 컨트롤의 ID |
HIWORD(wParam) |
컨트롤이 보내주는 통지 메시지, 메뉴가 선택된 경우는 0이 되며 액셀러레이터가 선택된 경우는 1이 됩니다. |
따라서 위의 작성된 메뉴에
case WM_COMMAND:
switch(LOWORD(wParam))
{
case 만든 메뉴 ID:
수행하고자 하는 작업
break;
}
return 0;
이렇게 작성하면 메뉴를 사용할 수 있습니다.
도형 메뉴를 상위 메뉴로 만들고 하위 메뉴로 100,100 에서 200,200으로 사각형, 원, 선을 그려주는 예제 만들기
1. 먼저 리소스에서 아래와 같이 메뉴를 추가합니다.
도형
사각형 – ID_RECT
원 – ID_ELLIPSE
선 – ID_LINE
2. WinMain 함수의 메뉴 부분을 수정하여 메뉴가 화면에 표시되는지 확인합니다.
wndclass.lpszMenuName = MAKEINTRESOURCE(IDR_MENU1);
3. 각각의 메뉴가 해야 할 일을 WM_COMMAND 메시지에 작성합니다.
HDC hdc;
PAINTSTRUCT ps;
static int flag = 0;
switch(message)
{
case WM_COMMAND:
switch(LOWORD(wParam))
{
case ID_RECT:
flag = 1;
InvalidateRect(hwnd,NULL,TRUE);
break;
case ID_ELLIPSE:
flag = 2;
InvalidateRect(hwnd,NULL,TRUE);
break;
case ID_LINE:
flag = 3;
InvalidateRect(hwnd,NULL,TRUE);
break;
}
return 0;
case WM_PAINT:
hdc = BeginPaint(hwnd,&ps);
if(flag == 1)
{
Rectangle(hdc,100,100,200,200);
}
else if(flag == 2)
{
Ellipse(hdc,100,100,200,200);
}
else if(flag == 3)
{
MoveToEx(hdc,100,100,NULL);
LineTo(hdc,200,200);
}
EndPaint(hwnd,&ps);
break;
case WM_DESTROY:
PostQuitMessage(0);
return 0;
}
7. 액셀러레이터
액셀러레이터(Accelerator)는 쉽게 말해서 단축키입니다.
메뉴 이름에 &를 넣어 Alt키와 함께 사용하는 키를 단축키라고 하며 여기서 말하는 Accelerator 와는 의미가 조금 다릅니다.
단축키는 반드시 Alt키와 함께 사용해야 하며 메뉴에 있는 항목을 키보드로 선택하는 빠른 방법이지만 액셀러레이터는 메뉴와 상관없이 언제든지 사용할 수 있다는 점에 있어서 차이가 있습니다.
엑셀러레이터 작성 방법
메뉴를 만들 때와 같은 방법으로 리소스추가를 선택하고 리소스 리스트에서 Accelerator를 선택합니다.
새로 만든 액셀러레이터 테이블이므로 아직 정의되어 있는 액셀러레이터가 없으며 빈칸만 하나 있습니다.
이 빈칸을 더블 클릭하면 액셀러레이터를 편집할 수 있는 속성 편집기가 열립니다.
ID
액셀러레이터의 ID이며 프로그램 소스에서 액셀러레이터를 참조할 때 이 값을 사용합니다.
메뉴의 ID를 작성하는 방법과 동일한 규칙대로 ID를 작성합니다.
기존 메뉴에 있는 ID를 연결하고자 하는 경우에는 드롭 다운 리스트를 열어 ID를 선택하면 됩니다.
기존에 없는 ID이면 직접 입력합니다.
보조키
같이 누를 키입니다.
키
액셀러레이터로 사용할 키를 선택합니다.
가상키를 사용하려면 드롭 다운 리스트를 열어 선택하고 알파벳 키나 숫자 키를 선택하려면 바로 아래쪽의 Next Key Typed버튼을 누른 후 원하는 키를 키보드에서 누르면 됩니다.
형식
Key값이 아스키 코드 값인지 가상키 코드 값인지를 설정합니다.
보통 가상키 코드를 많이 사용합니다.
다음은 만들어진 리소스를 코드에서 사용하도록 소스를 변경해 주어야 합니다.
액셀러레이터의 ID를 메뉴의 ID와 같다면 WndProc의 WM_COMMAND는 수정할 필요가 없습니다.
WinMain의 선두에 hAccel 변수를 선언해 주고 메시지 루프만 다음과 같이 수정해 주면 됩니다.
이는 윈도우의 메시지 루프에서 액셀러레이터를 키보드 메시지인지 번역하기 전에 수행하기 위해서 작성합니다.
HACCEL hAccel;
hAccel=LoadAccelerators(hInstance,MAKEINTRESOURCE(IDR_ACCELERATOR1));
while(GetMessage(&msg,0,0,0))
{
if (!TranslateAccelerator(hwnd,hAccel,&msg))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
}
return msg.wParam ;
HACCEL LoadAccelerators(HINSTANCE hInstance, LPCTSTR lpTableName );
이 함수는 리소스로부터 액셀러레이터 테이블을 읽어 들이게 됩니다.
두 번째 인수 lpTableName은 액셀러레이터 테이블의 이름 문자열 포인터이되 사용자가 작성한 액셀러레이터 테이블 IDR_ACCELERATOR1은 정수 값 이므로 MAKEINTRESOURCE 매크로를 사용해서 변경을 해 주어야 합니다.
이 함수는 리소스에서 액셀러레이터 테이블을 읽은 후 그 핸들 값을 리턴해 줍니다.
이 핸들 값을 hAccel이라는 변수에 대입해 두면 다음부터 hAccel을 통해 액셀러레이터 테이블을 읽을 수 있습니다.
int TranslateAccelerator(HWND hwnd, HACCEL hAccTable, LPMSG lpMsg );
이 함수는 MSG 구조체 메시지를 액셀러레이터 메시지로 변환해주는 역할을 합니다.
8. Pop-up 메뉴
마우스 오른쪽 버튼을 누르면 나타나는 메뉴
WM_CONTEXTMENU: 마우스 오른쪽 버튼을 누를 때 화면에 메뉴를 출력하는 메시지
lParam – 클릭한 위치
TrackPopupMenu함수를 이용해서 구현합니다.
TrackPopupMenu( UINT nFlags, int x, int y, CWnd* pwnd, LPCRECT lpRect = NULL );
hMenu는 팝업 메뉴의 핸들입니다.
uFlags는 팝업 메뉴를 출력할 옵션
x, y는 팝업 메뉴를 출력할 좌표입니다.
nReserved는 예약 영역으로 0으로 주면 됩니다.
hwnd는 팝업 메뉴의 부모 윈도우 핸들을 주어야 합니다.
팝업 메뉴가 선택되었을 때 이 윈도우 핸들로 WM_COMMAND 메시지가 전달된다.
메뉴에 대한 핸들 얻기
메뉴 핸들 = LoadMenu(인스턴스 핸들, MAKEINTRESOURCE(리소스이름));
메뉴 중 특정 부분 얻기
메뉴 핸들 = GetSubMenu(hmenu, 0);
Popup 메뉴 만드는 방법
1. 하나의 메뉴를 삽입합니다.
2. 메뉴를 구성하고 WM_COMMAND 메시지에 메뉴가 해야 할 일을 작성합니다.
3. WndProc함수에서
HMENU hmenu;
HMENU hmenuPopup;
int x, y;
변수를 생성합니다.
4. WM_CONTEXTMENU 메시지에 작성합니다.
HMENU hmenu;
HMENU hmenuPopup;
int x, y;
static int flag;
HDC hdc;
PAINTSTRUCT ps;
switch(message)
{
case WM_CONTEXTMENU:
x = LOWORD(lParam);
y = HIWORD(lParam);
hmenu = LoadMenu(hin, MAKEINTRESOURCE(IDR_MENU1));
hmenuPopup = GetSubMenu(hmenu, 0);
TrackPopupMenu(hmenuPopup, TPM_LEFTALIGN | TPM_TOPALIGN
| TPM_LEFTBUTTON | TPM_RIGHTBUTTON, x, y,
0, hwnd, NULL);
return 0;
case WM_COMMAND:
switch(LOWORD(wParam))
{
case ID_RECT:
flag = 1;
InvalidateRect(hwnd,NULL,TRUE);
break;
case ID_ELLIPSE:
flag = 2;
InvalidateRect(hwnd,NULL,TRUE);
break;
case ID_LINE:
flag = 3;
InvalidateRect(hwnd,NULL,TRUE);
break;
}
return 0;
case WM_PAINT:
hdc = BeginPaint(hwnd,&ps);
if(flag == 1)
{
Rectangle(hdc,100,100,200,200);
}
else if(flag == 2)
{
Ellipse(hdc,100,100,200,200);
}
else if(flag == 3)
{
MoveToEx(hdc,100,100,NULL);
LineTo(hdc,200,200);
}
EndPaint(hwnd,&ps);
break;
case WM_DESTROY:
PostQuitMessage(0);
return 0;
}
9. 시스템 메뉴 만들기
프로그램의 왼쪽 아이콘 부분을 클릭하면 시스템 메뉴가 만들어져 있습니다.
이 메뉴 처리는 WM_SYSCOMMAND메시로 처리하며 이 때 LOWORD(wParam)이 누른 메뉴의 ID를 전달합니다.
이 메뉴 핸들은 GetSystemMenu(hwnd, FALSE)로 구할 수 있습니다.
메뉴 핸들에 메뉴를 추가할 때는
AppendMenu(HMENU hMenu, UINT uFlags, UINT_PTR uIDNewItem, LPCTSTR lpNewItem)
hMenu: 삽입할 메뉴 핸들
uFlags: 추가할 메뉴 옵션
MF_CHECKED: 체크 상태
MF_DISABLED: 비 활성화 상태
MF_ENABLED: 활성화 상태
MF_GRAYED: 회색 상태
MF_POPUP: 팝업 메뉴
MF_SEPARATOR: 구분선
MF_STRING: 문자열 메뉴
uIDNewItem: 메뉴 ID
lpNewItem: 메뉴에 보여질 텍스트
#define ID_SYSMENU 1
LRESULT CALLBACK WndProc (HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
HMENU hMenu;
switch (message)
{
case WM_CREATE:
hMenu = GetSystemMenu(hwnd,FALSE);
AppendMenu(hMenu,MF_SEPARATOR,0,NULL);
AppendMenu(hMenu,MF_STRING,ID_SYSMENU,TEXT("시스템메뉴확장"));
return 0;
case WM_SYSCOMMAND:
switch(LOWORD(wParam))
{
case ID_SYSMENU:
MessageBox(hwnd,TEXT("시스템메뉴확장"), TEXT("SYSTEM MENU"),MB_OK);
return 0;
}
break;
case WM_DESTROY:
PostQuitMessage(0);
return 0;
}
return DefWindowProc (hwnd, message, wParam, lParam) ;
}
'C & C++ > C & C++' 카테고리의 다른 글
[API] 윈도우 관련 함수와 메시지 (0) | 2011.04.25 |
---|---|
API 대화상자 (0) | 2011.04.25 |
[API] API 메시지 처리 (0) | 2011.04.25 |
[API] 화면 출력 API (0) | 2011.04.25 |
API 란 무엇인가? (0) | 2011.04.25 |
댓글