모달리스 대화상자
모달리스는 대화상자는 부모 윈도우를 선택할 수 있으며, 그 대표적인 예로는 찾기대화상자 이다.
CreateDialog() 함수 : 모달리스 대화상자 생성
HWND CreateDialog( HINSTANCE hInstance, // 대화상자 인스턴스 핸들 LPCTSTR lpTemplate, // 대화상자 ID HWND hWndParent, // 이 대화상자를 소유하는 오너 윈도우의 핸들이다 DLGPROC lpDialogFunc // 대화상자로 전달되는 메시지를 처리하는 메시지 처리 함수의 포인터를 지정 ); |
BOOL ShowWindow() 함수 : 모달리스 대화상자를 보이거나 숨기기
BOOL ShowWindow( HWND hWnd, // 대상 윈도우 핸들 int nCmdShow // 지정하고자 하는 보이기 상태이며 다음 값중 하나를 지정 ); |
값 | 설명 |
SW_FORCEMINIMIZE |
2000 이후에만 쓸 수 있는 플레그이다. 윈도우를 소유한 스레드가 블록된 상태에서도 윈도우를 최소화시킨다. |
SW_HIDE |
윈도우를 숨긴다. |
SW_MAXIMIZE |
윈도우를 최대화시킨다. |
SW_MINIMIZE |
윈도우를 최소화시키며 다음 Z순서를 가지는 윈도우가 활성화된다. |
SW_RESTORE | 최대, 최소화된 윈도우를 이전 위치로 복구한다. |
SW_SHOW |
윈도우를 활성화하며 보인다. |
SW_SHOWDEFAULT |
STARTUPINFO 구조체가 지정하는 보이기 상태로 만든다. |
SW_SHOWMAXIMIZED |
윈도우를 최대화된 상태로 활성화한다. |
SW_SHOWMINIMIZED |
윈도우를 최소화한 상태로 활성화한다. |
SW_SHOWMINNOACTIVE |
윈도우를 최소화 상태로 보이며 활성화 상태는 변경되지 않는다. |
SW_SHOWNA |
윈도우를 헌재 상태로 보이며 활성화 상태는 변경되지 않는다. |
SW_SHOWNOACTIVATE |
최근 크기와 위치에 윈도우를 보이며 활성화 상태는 변경되지 않는다. |
SW_SHOWNORMAL |
윈도우를 보이며 활성화한다. 만약 윈도우가 최소화되어 있거나 최대화되어 있다면 윈도우를 원래 크기대로 복구한다. 윈도우를 처음 화면에 보일 때는 이 플래그를 사용해야 한다. |
DestroyWindow() 함수 : 모달리스 대화상자 종료
BOOL DestroyWindow( HWND hWnd ); |
IsWindow() 함수 : 매개변수로 주어진 윈도우 핸들 값이 유효한지를 검사하는 함수
BOOL IsWindow(HWND hWnd); |
오른쪽버튼을 클릭하여 모달리스 대화상자를 띄어보자.
LRESULT CALLBACK WndProc(HWND hwnd, UINT iMsg, WPARAM wParam, LPARAM lParam) { HWND hDlg = NULL; switch (iMsg) { case WM_CREATE: break; case WM_RBUTTONDOWN: if (!IsWindow(hDlg)) // hDlg 변수가 윈도우 핸들 값이 유효한지 검사 { hDlg = CreateDialog(hInst, MAKEINTRESOURCE(IDD_DIALOG1), hwnd, DlgProc); ShowWindow(hDlg, SW_SHOW); } break; case WM_DESTROY: PostQuitMessage(0); break; } return DefWindowProc(hwnd, iMsg, wParam, lParam); } BOOL CALLBACK DlgProc(HWND hDlg, UINT iMsg, WPARAM wParam, LPARAM lParam) { static HWND hList; static int selection; TCHAR name[20];
switch (iMsg) { case WM_INITDIALOG: hList = GetDlgItem(hDlg, IDC_LIST_NAME); return 1; case WM_COMMAND: switch (LOWORD(wParam)) { case IDC_BUTTON_INSERT: GetDlgItemText(hDlg, IDC_EDIT_NAME, name, 20); if (_tcscmp(name, _T(""))) SendMessage(hList, LB_ADDSTRING, 0, (LPARAM)name); return 0; case IDC_BUTTON_DELETE: SendMessage(hList, LB_DELETESTRING, selection, 0); return 0; case IDC_LIST_NAME: if (HIWORD(wParam) == LBN_SELCHANGE) selection = (int)SendMessage(hList, LB_GETCURSEL, 0, 0); break; case IDCANCEL: EndDialog(hDlg, 0); return 0; } break; } return 0; } |
실행 결과]
공용 컨트롤
공용 컨트롤을 사용하기 위해서는 공용 컨트롤의 헤더와 라이브러리가 필요한다. 헤더는 commctrl.h로 코드상의 해더 선언부에 #include <commctrl.h>를 선언해야 한다.
라이브러리의 포함은 프로젝트의 [속성] - [구성 속성] - [링커] - [입력]에 들어가면 오른쪽 패널의 [추가 종속성]에 comctl32.lib를 입력하고 [확인] 버튼을 누른다.
리스트 컨트롤
칼럼 만들기 : LVCOLUMN 구조체
typedef struct _LVCOLUMN { UIN mask; // 마스크 int fmt; // 칼럼 정렬 플래그 int cx; // 칼럼의 가로 크기 LPTSTR pszText; // 칼럼 텍스트 int cchTextMax; // 칼럼 텍스트의 최대 길이 int iSubItem; // 칼럼 번호 } LVCOLUMN, *LPLVCOLUMN; |
mask 값은 fmt나 cx, pszText, iSubItem 등의 정보를 참조할 것인지 결정하는 플래그이다.
대표적으로 다음 네 가지가 많이 사용된다.
값 | 내용 |
LVCF_FMT | fmt 값을 유효화 한다. |
LVCF_SUBITEM | iSubItem 값을 유효화 한다. |
LVCF_TEXT | pszText 값을 유효화 한다. |
LVCF_WIDTH | cx 값을 유효화 한다. |
fmt의 경우는 칼럼의 텍스를 어떻게 정렬 시키느냐의 플래그로써 대표적으로 다음 세가지가 주로 사용된다.
값 | 내용 |
LVCFMT_LEFT | 칼럼 텍스트를 왼쪽 정렬 |
LVCFMT_RIGHT | 칼럼 텍스트를 오른쪽 정렬 |
LVCFMT_CENTER | 칼럼 텍스트를 가운데 정렬 |
칼럼 만들기 예
LVCOLUMN lvCol; // 구조체 타입의 변수 선언 memset(&lvCol, 0, sizeof(LVCOLUMN)); // lvCol의 모든 필드를 0으로 초기화 lvCol.mask = LVCF_FMT | LVCF_WIDTH | LVCF_TEXT | LVCF_SUBITEM; lvCol.fmt = LVCFMT_LEFT; // 칼럼을 왼쪽정렬 lvCol.cx = 90; // 칼럼의 폭을 90픽셀로 설정 lvCol.iSubItem = i; // 칼럼의 인덱스 번호를 지정 SendMessage(hList, LVM_INSERTCOLUMN, (WPARAM)i, (LPARAM)&lvCol);
|
memset()함수 : 어떤 메모리의 시작점부터 연속된 범위를 툭정 값으로 모두 지정하고 싶을 때 사용하는 함수
void * memset ( |
칼럼이 만들어지면 리스트 컨트롤의 각 항목에 데이터를 입력해야 하는데 데이터를 입력하려면 LVITEM구조체가 필요하다.
칼럼에 항목에 데이터 입력 : LVITEM 구조체
typedef struct _LVITEM { UINT mask; // 마스크용 플래그 int iItem; //항목의 인덱스번호 지정 } LVITEM, *LPLVITEM; |
mask 플래그
값 | 내용 |
LVIF_STATE | state 필드 |
LVIF_TEXT | pszText 필드 |
LVIF_IMAGE | iImage 필드 |
LVIF_PARAM | lParam 필드 |
리스트 컨트롤에 새로운 항목(행)을 추가히기
int ListView_InsertItem ( HWND hWnd, // 목록보기 컨트롤에 대한 핸들 const LPLVITEM pitem // 목록보기 항목의 속성을 지정 하는 LVITEM 구조에 대한 포인터로 iItem에 새로운 항목이 삽입 ); |
리스트 컨트롤의 특정 항목에 텍스트 출력하기
VOID ListView_SetItemText ( HWND hWnd, // 목록보기 컨트롤에 대한 핸들 int i, // 목록보기 항목의 0부터 시작하는 인덱스 int iSubItem, // 하위 항목은 1부터 시작하는 인덱스로 항목 레이블을 설정하려면 iSubItem 을 0으로 설정 LPCTSTR pszText // 새 텍스트를 포함하는 null로 끝나는 문자열에 대한 포인터 ); |
WM_NOTIFY 메시지는 일반적으로 자식윈도우(컨트롤등)가 자신에게 일어난 여러가지 상황을 부모윈도우(예, 대화상자)에게 전달할때 사용하는 메시지이다.
WM_NOTIFY 메시지의 정보는 lParam에 저장되고 lParam의 정보를 보려면 NMHDR타입에 대한 포인터형인 LPNMHDR 타입으로 형 변환하거나 NMLISTVIEW 구조체의 포인터형인 LPNMLISTVIEW 타입으로 형 변환을 해야 한다.
LPNMHDR로 형 변환을 한 경우에는 변화가 일어난 컨트롤의 윈도우 핸들 값과 변화 내용을 알 수 있다.
LPNMLISTVIEW로 형 변환을 하면 리스트 컨트롤의 어떤 항목에 변화가 있는지 알 수 있다.
LPNMHDR 구조체
typedef struct tagNMHDR { HWND hwndFrom; // 변화가 발생해 메시지를 보내는 컨트롤의 원도우 핸들 값을 저장 UINT_PTR idFrom; // 메시지를 보낸 컨트롤의 ID UINT code; // 컨트롤에 발생한 변화 내용을 담고 있다. } NMHDR; |
리스트 컨트롤에서 발생하는 코드
LVN_ITEMCHANGING | 리스트 컨트롤의 항목에 변화 발생 |
LVN_KEYDOWN | 리스트 컨트롤에서 키보드를 누름 |
LVN_INSERTITEM | 리스트 컨트롤에 새 항목이 추가됨 |
LVN_DELETEITEM | 리스트 컨트롤의 항목 하나가 삭제됨 |
LVN_COLUMNCLICK | 리스트 컨트롤의 특정 칼럼이 선택됨 |
LPNMLISTVIEW 구조체
typedef struct LPNMLISTVIEW { NMHDR hdr; // WM_NOTIFY와 함께 변화가 일어난 컨트롤의 원도우 핸들 값과 변화내용의 정보 int iItem; // 리스트 컨트롤의 몇 번째 행의 변화가 있었는지를 알려주는 인덱스 값 int iSubItem; // 리스트 컨트롤의 몇 번째 열에 변화가 있었는지를 알려주는 인덱스 값 UINT uNewState; // 변경된 상태 UINT uOldState; // 변경되기 전의 상태 UINT uChanged; // 변경된 항목을 가르키는 비트 마스크 (LVITEM의 MASK와 같다) POINT ptAction; // 통지 메세지 발생 시점의 마우스 포인터 위치이며 드래그 메세지에서만 사용 LPARAM lParam; // LPARAM값 } NMLISTVIEW, *LPNMLISTVIEW; |
리스트 컨트롤의 특정 항목에서 텍스트를 얻어오는 함수
ListView_GetItemText() 함수
void ListView_GetItemText ( HWND hwnd, // 리스트 컨트롤 윈도우 핸들 int iIem, // 특정 항목의 위치(행) int iSubItem, // 특정 항목의 위치(열) LPTSTR pszText, // 텍스트 저장 버퍼 주소 int cchTextMax // 버퍼 길이 ); |
리스트 컨트롤의 특정 항목을 삭제하는 함수
BOOL ListView_DeleteItem() 함수
BOOL ListView_DeleteItem( HWND hwnd, // 리스트 컨틀로 윈도우 핸들 int iItem // 특정 항목의 위치(행) ); |
리스트 컨트롤에 칼럼만들기
#include <windows.h> #include <TCHAR.H> #include <commctrl.h> #include "resource.h" ... void MakeColumn(HWND hDlg); ...
LRESULT CALLBACK WndProc(HWND hwnd, UINT iMsg, WPARAM wParam, LPARAM lParam) { HWND hDlg = NULL; switch (iMsg) { case WM_CREATE: break; case WM_RBUTTONDOWN: if (!IsWindow(hDlg)) { hDlg = CreateDialog(hInst, MAKEINTRESOURCE(IDD_DIALOG1), hwnd, DlgProc); ShowWindow(hDlg, SW_SHOW); } break; case WM_DESTROY: PostQuitMessage(0); break; } return DefWindowProc(hwnd, iMsg, wParam, lParam); }
BOOL CALLBACK DlgProc(HWND hDlg, UINT iMsg, WPARAM wParam, LPARAM lParam) { switch (iMsg) { case WM_INITDIALOG: MakeColumn(hDlg); return 1; case WM_COMMAND: switch (LOWORD(wParam)) { case IDCLOSE: DestroyWindow(hDlg); hDlg = NULL; return 0; case IDCANCEL: DestroyWindow(hDlg); hDlg = NULL; return 0; } break; } return 0; }
void MakeColumn(HWND hDlg) { LPCWSTR name[2] = { _T("이름"), _T("전화번호") }; LVCOLUMN lvCol = { 0, }; HWND hList; int i; hList = GetDlgItem(hDlg, IDC_LIST_MEMBER); lvCol.mask = LVCF_FMT | LVCF_WIDTH | LVCF_TEXT | LVCF_SUBITEM; lvCol.fmt = LVCFMT_LEFT;
for (i = 0; i < 2; i++) { lvCol.cx = 90; lvCol.iSubItem = i; lvCol.pszText = (LPTSTR)name[i]; SendMessage(hList, LVM_INSERTCOLUMN, (WPARAM)i, (LPARAM)&lvCol); } } |
실행 결과]