2011년9월27일_winAPI_대화상자이론, 모달형 대화상자 예제, 대화상자기반의 프로그램(Dialog Base)



● 대화상자란?

image
[스크린샷] 비주얼 스튜디오 6.0의 Option 대화상자

대화상자(Dialog Box)는 프로그램과 사용자간의 대화, 곧 명령 및 정보 전달을 위한 특별한 윈도우이다.
대화상자에는 버튼, 에디트 등의 컨트롤들이 배치되는데 그래서 대화상자를 컨트롤의 컨테이너라고도 한다.
상기의 스크린샷과 같이 대화상자는 여러 가지 컨트롤이 배치되어 있어 마치 종합선물세트와 같다.
이런 컨트롤들을 메인 윈도우에서 따로따로 배치하여 관리한다면 프로그래밍도 불편하고 사용자도 불편할 것이다.
대화상자를 이용하면 보기 좋게 사용자 인터페이스를 만들 수 있다.



● 동작방식에 따른 분류

① 모달형
모달(Modal)형은 대화상자를 닫기 전에 다른 윈도우로 전환할 수 없으며 반드시 확인(또는 OK)버튼이나 취소(또는 Cancel)버튼을 눌러,
대화상자를 닫아야 다른 윈도우로 전환할 수 있다. 비주얼 스튜디오 6.0의 Option대화상자도 모달 대화상자이다.

② 모달리스형
모달리스(Modaless)형은 대화상자를 열러 놓은 채로 다른 윈도우로 전환할 수 있는 대화상자이다.
일반적으로 많이 사용되지는 않지만 메모장의 찾기 대화상자가 모달리스형이다.

image image
[스크린샷] 찾기 대화상자가 포커스를 얻은 상태                        [스크린샷] 메인 윈도우인 메모장이 포커스를 얻은 상태

메모장(notepad)에서 Ctrl + F키를 눌러 일치하는 단어를 찾은 후 마우스를 클릭하여 메인윈도우를 선택하면,
편집창에서 수정도 가능하고 찾기 대화상자도 사라지지 않는다.
이렇게 메인윈도우의 내용과 대화상자의 내용을 동시에 보고자 할 때 모달리스형을 사용하면 되겠다.



● 대화상자를 만들기 위해 필요한 구성요소

① 대화상자 템플릿
  대화상자의 모양과 대화상자 내의 컨트롤 배치 상태가 저장되는 이진 정보이며 리소스로 작성된다.
개발자 스튜디오에 별도의 대화상자 편집기가 제공되므로 어렵지 않게 디자인 할 수 있다.

② 대화상자 프로시저
  윈도우 프로시저가 윈도우에서 발생하는 메시지를 처리하는 것과 마찬가지로 대화상자 프로시저는,
대화상자에서 발생하는 메시지를 처리한다. WndProc()에서 처리하는 것이 아니다. 따로 콜백함수를 정의해서 사용한다.



● windows API정복 page.226 예제: About  (핵심코드만 미리보기)
▷ 메시지맵

   1: typedef struct DLGMESSAGEMAP {
   2:     UINT iMessage;
   3:     BOOL (*lpfnMsgProc)(HWND, WPARAM, LPARAM);
   4: } DLGMESSAGEMAP;


▷ 다이어로그박스 메시지 처리함수

   1: BOOL CALLBACK AboutDlgProc(HWND hDlg, UINT iMessage, WPARAM wParam, LPARAM lParam)
   2: {
   3:     // 20110927 add
   4:     int i;
   5:  
   6:     static DLGMESSAGEMAP DMessageMaps[] = {
   7:         //메시지 추가할 것.
   8:         {WM_INITDIALOG, OnInitDialog},
   9:         {WM_COMMAND, OnDlgCommand}
  10:     };
  11:  
  12:     for(i = 0 ; i < sizeof(DMessageMaps) / sizeof(DMessageMaps[0]) ; ++i)
  13:     {
  14:         if(DMessageMaps[i].iMessage == iMessage)
  15:         {
  16:             return (*DMessageMaps[i].lpfnMsgProc)(hDlg, wParam, lParam);
  17:         }
  18:     }
  19:  
  20:     return FALSE;    //정의되어 있지 않은 메시지는 모두 FALSE, 정의된건 TRUE
  21: }


▷ MsgProc.cpp

   1: LRESULT OnLButtonDown(HWND hWnd, WPARAM wParam, LPARAM lParam)
   2: {
   3:     int iResult;
   4:  
   5:     // 리턴값은 어떤 버튼을 눌렀는지 확인. IDOK, IDCANCEL
   6:     iResult = DialogBox(g_hInst, MAKEINTRESOURCE(IDD_DIALOG1), hWnd, AboutDlgProc);    //대화상자 생성
   7:  
   8:     if(IDOK == iResult)
   9:     {
  10:         //
  11:         MessageBox(hWnd, TEXT("test"), TEXT("OK버튼 클릭"), MB_OK); 
  12:     }
  13:     else if(IDCANCEL == iResult)
  14:     {
  15:         //
  16:     }
  17:  
  18:     return 0;
  19: }
  20:  
  21: BOOL OnInitDialog(HWND hDlg, WPARAM wParam, LPARAM lParam)
  22: {
  23:     
  24:     return TRUE;
  25: }
  26:  
  27: BOOL OnDlgCommand(HWND hDlg, WPARAM wParam, LPARAM lParam)
  28: {
  29:     switch(LOWORD(wParam)) {
  30:     case IDOK:
  31:         EndDialog(hDlg, IDOK);
  32:         return TRUE;
  33:     case IDCANCEL:
  34:         EndDialog(hDlg, IDCANCEL);
  35:         return TRUE;
  36:     }
  37:  
  38:     return TRUE;
  39: }

<간단 소스코드 설명>

   6:     iResult = DialogBox(g_hInst, MAKEINTRESOURCE(IDD_DIALOG1), hWnd, AboutDlgProc);    //대화상자 생성
  31:         EndDialog(hDlg, IDOK);
  34:         EndDialog(hDlg, IDCANCEL);

g_hInst는 대화상자 리소스를 가진 인스턴스의 핸들이고 WinMain( ) 호출시 hInstance라는 첫 번째 인자로 받는다.
MAKEINTRESOURCE( ) 매크로함수는 다들 아시다시피 정수로 된 ID를 문자열로 형변환하는 함수이다.
hWnd는 부모윈도우의 핸들이고, AboutDlgProc는 대화상자에서 발생하는 메시지를 처리하는 콜백함수의 이름으로 시작주소다.
즉, 이 프로그램의 리소스를 사용해 IDD_DIALOG1이라는 대화상자를 생성하고,
    이 대화상자의 메시지는 AboutDlgProc( )가 도맡아 처리한다.
    대화상자가 열려 있을 때는 DialogBox( )에서 블로킹되어 프로그램이 다음으로 진행되지 못 하는 모달방식이고,
    대화상자를 EndDialog( )로 닫으면 DialogBox( )가 리턴되어 iResult에 EndDialog( )의 두 번째 인자가 저장된다.


▷ 리소스

image  ID는 IDD_DIALOG1

전체소스코드 다운로드 : 0927_About.zip

<실행결과>

image image image
[스크린샷] 메인 윈도우                       [스크린샷] 배고파 대화상자                 [스크린샷] OK버튼을 누를 경우 결과




● 윈도우 프로시저의 리턴값  ┬  메시지처리 O  → 0을 리턴
                                    └  메시지처리 X   → DefWindowProc( )로 보냄
● 대화상자 프로시저의 리턴값 ┬ 메시지처리 O  → TRUE리턴
                                      └ 메시지처리 X  → FALSE리턴

● 대화상자 프로시저는 WM_CREATE대신 WM_INITDIALOG메시지를 받아 들이고,
   일반 윈도우와 마찬가지로 LOWORD(wParam)에 메시지를 보낸 컨트롤의 ID가 전달되며,
                                   HIWORD(wParam)에 통지코드가 전달된다.




● windows API정복 page.230   대화상자 프로젝트

image
[스크린샷] 윈도우에서 유용한 프로그램인 계산기

상기와 같이 대화상자가 메인 윈도우가 되는 형태의 프로그램을 대화상자 기반의 프로그램(Dialog Base)이라고 하며,
컨트롤을 많이 사용하는 프로그램들이 주로 대화상자 기반으로 만들어진다.



● 예제: DlgBase
▷ main.cpp

   1: // winAPI p.231 DlgBase
   2: // 2011년 9월 27일 작성 
   3: // 작성자: 김수만
   4:  
   5: #include <windows.h>    // 모든 API함수들의 원형과 사용하는 상수들이 정의되어 있음.
   6: #include "MsgProc.h"    //add
   7: #include "resource.h"
   8:  
   9: //add
  10: typedef struct MESSAGEMAP {
  11:     UINT iMessage;
  12:     LRESULT (*lpfnMsgProc)(HWND, WPARAM, LPARAM);
  13: } MESSAGEMAP;
  14:  
  15: typedef struct DLGMESSAGEMAP {
  16:     UINT iMessage;
  17:     BOOL (*lpfnMsgProc)(HWND, WPARAM, LPARAM);
  18: } DLGMESSAGEMAP;
  19:  
  20:  
  21: //시작함수.
  22: int APIENTRY WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpszCmdParam, int nCmdShow)
  23: {
  24:     DialogBox(hInstance, MAKEINTRESOURCE(IDD_DIALOG1), HWND_DESKTOP, MainDlgProc);
  25:     return 0;
  26: }
  27:  
  28:  
  29:  
  30: BOOL CALLBACK MainDlgProc(HWND hDlg, UINT iMessage, WPARAM wParam, LPARAM lParam)
  31: {
  32:     // 20110927 add
  33:     int i;
  34:  
  35:     static DLGMESSAGEMAP DMessageMaps[] = {
  36:         //메시지 추가할 것.
  37:         {WM_INITDIALOG, OnInitDialog},
  38:         {WM_COMMAND, OnDlgCommand}
  39:     };
  40:  
  41:     for(i = 0 ; i < sizeof(DMessageMaps) / sizeof(DMessageMaps[0]) ; ++i)
  42:     {
  43:         if(DMessageMaps[i].iMessage == iMessage)
  44:         {
  45:             return (*DMessageMaps[i].lpfnMsgProc)(hDlg, wParam, lParam);
  46:         }
  47:     }
  48:  
  49:     return FALSE;    //정의되어 있지 않은 메시지는 모두 FALSE, 정의된건 TRUE
  50: }


<소스코드설명>

  24:     DialogBox(hInstance, MAKEINTRESOURCE(IDD_DIALOG1), HWND_DESKTOP, MainDlgProc);

WinMain( )에는 24행의 DialogBox( )호출문 밖에 없다. 매우 간단한데;;;
첫 번째 인자는 인스턴스의 핸들로 다들 아실테고,
두 번째 인자도 리소스ID로 다들 아실거고,
세 번째 인자는 HWND_DESKTOP으로 NULL을 의미한다. 즉, 부모 윈도우자리에 NULL을 넣으니 부모가 없다는 것. 독립했삼.
네 번째 인자는 대화상자 메시지 처리함수이다.
 

▷ 리소스

image