API 대화상자

IT/개발공부 / / 2020. 9. 19. 20:06
728x90
반응형

대화상자는 프로그램과 사용자간의 대화, 곧 명령 및 정보 전달을 위한 특별한 윈도우입니다. 대화상자에는 버튼, 에디트 등의 컨트롤들이 배치되며 사용자는 대화상자를 호출한 후 컨트롤을 통해 자신의 의사를 표시하고 명령을 내리며 프로그램은 대화상자에 배치된 컨트롤들을 통해 현재 상태를 사용자에게 보여줍니다.

 

대화상자는 동작 방식에 따라 모달형과 모달리스형으로 나뉩니다.

 

모달형 대화상자

모달(Modal)형은 대화상자를 닫기 전에 다른 윈도우로 전환할 수 없으며 반드시 확인 또는 취소 버튼을 눌러 대화상자를 닫아야 다른 윈도우로 전환할 수 있습니다.

 

대화상자를 구현하기 위해서는 2가지가 있어야 합니다.

  • 대화상자 템플릿 : 대화상자의 모양과 대화상자 내의 컨트롤 배치 상태가 저장되는 리소스 형태로 작성됩니다. 편집기로 제공되므로 어렵지 않게 디자인 할 수 있습니다.
  • 대화상자 프로시저 : 윈도우 프로시저가 윈도우에서 발생하는 메시지를 처리하는 것과 마찬가지로 대화상자 프로시저는 대화상자에서 발생하는 메시지를 처리합니다.

아래는 대화상자 프로시저 모양은 아래와 같습니다.

BOOL CALLBACK DlgProc(HWND hDlg, UINT msg, WPARAM wParam, LPARAM lParam)
{
   switch(msg) 
   {
   
   case WM_INITDIALOG: { }
   break;
   
   case WM_COMMAND:
   
   switch(LOWORD(wParam))
   {
      case IDCANCEL:
      EndDialog(hDlg, IDCANCEL);
      return TRUE;
   }
   return FALSE; // 메세지 처리를 안한경우..
}

프로시저이기 때문에 리턴값이나 인자는 메인 프로시저와 동일합니다. 단, 아래와 같이 몇가지 차이점이 있습니다.

 

  1. 처리하지 않은 메시지인 경우 return 반드시 FALSE 를 해야합니다.
  2. WM_COMMAND 의 IDCANCEL 이벤트 발생시 반드시 EndDialog를 호출해야 합니다. 이 부분이 Main 프로시저의 종료 코드와 동일한 역할을 수행합니다.
  3. 최초 호출되는 부분은 WM_INITDIALOG 부분입니다. 따라서 이 곳에서 초기화를 수행합니다.

 

typedef struct tagDATA{
   TCHAR str[20];
   int num;
}DATA;

BOOL CALLBACK DlgProc(HWND hDlg, UINT msg, WPARAM wParam, LPARAM lParam){
   static DATA *pData;
   switch(msg)
   {
      // Dialog가 처음 나타날때 발생. 각 콘트롤을 초기화 한다.
      case WM_INITDIALOG: {
         pData = (DATA*)lParam;
         SetDlgItemText(hDlg, IDC_EDIT1, pData->str);
         SetDlgItemInt(hDlg, IDC_EDIT2, pData->num, 0);
         }
         break;
         
         case WM_COMMAND:
         switch(LOWORD(wParam)) {
            case IDOK:
            GetDlgItemText(hDlg, IDC_EDIT1, pData->str, sizeof(pData->str));
            pData->num = GetDlgItemInt(hDlg, IDC_EDIT2, 0, 0);
            EndDialog(hDlg, IDOK);
            return TRUE;
            
            case IDCANCEL:
            EndDialog(hDlg, IDCANCEL);
            return TRUE;
         }
      }
      return FALSE; // 메세지 처리를 안한경우..
   }

LRESULT CALLBACK WndProc( HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam){
   switch( msg ) {
      case WM_LBUTTONDOWN:
      {
         DATA data = {TEXT("홍길동"), 20 };
         UINT ret = DialogBoxParam( GetModuleHandle(0),// hinstance
         MAKEINTRESOURCE(IDD_DIALOG1),
         hwnd, // 부모
         DlgProc, // 메세지 함수.
         (LPARAM)&data); // WM_INITDIALOG의 lParam로 전달된다.
         if ( ret == IDOK ) {        
         // 이제 Dialog에 입력한 값은 data에 있다.
         TCHAR buf[128];
         wsprintf(buf, TEXT("%s / %d"), data.str, data.num);
         SetWindowText(hwnd, buf);
      }
   }
   return 0;

자식이 호출되었을때 부모가 전달한 데이터를 출력됨을 알수있고, 모달 대화상자에서 정보를 수정해 확인 버튼을 클릭했을 때 부모의 타이틀 바에 자식에게서 전달 받은 정보가 출력되는 예제입니다.

 

모달리스형 대화상자

모달리스(Modaless)형은 대화상자를 열어 놓은 채로 다른 윈도우로 전환할 수 있는 대화상자입니다. 일반적으로 모달형에 비해 많이 사용되지는 않지만 필요에 의해 사용되어 집니다. 모달리스형은 다른 작업ㅇ르 하면서 열려 있을 수 있기 때문에 모달형 보다는 프로그래밍할 때 고려해야 할 사항이 더 많이 있습니다.

 

아래는 모달리스형 대화상자 구현 예제입니다.

typedef struct tagDATA{
   TCHAR str[20];
   int num;
}DATA;

//------------------------------------
HWND g_hDlg; // Dialog 의 핸들
#define WM_APPLY WM_USER + 100
//------------------------------------

BOOL CALLBACK DlgProc(HWND hDlg, UINT msg, WPARAM wParam, LPARAM lParam){
   static DATA *pData;
   switch(msg)
   {
      // Dialog가 처음 나타날때 발생. 각 콘트롤을 초기화 한다.
      case WM_INITDIALOG:
      {
         pData = (DATA*)lParam;
         SetDlgItemText(hDlg, IDC_EDIT1, pData->str);
         SetDlgItemInt(hDlg, IDC_EDIT2, pData->num, 0);
         HWND h = GetDlgItem(hDlg, IDOK);
         SetWindowText(h, TEXT("적용"));
      }
      break;
      
      case WM_COMMAND:
      switch(LOWORD(wParam))
      {
         case IDOK: //적용
         GetDlgItemText(hDlg, IDC_EDIT1, pData->str, sizeof(pData->str));
         pData->num = GetDlgItemInt(hDlg, IDC_EDIT2, 0, 0);
         SendMessage( GetParent( g_hDlg), WM_APPLY, 0, 0);
         return TRUE;
         
         case IDCANCEL:
         EndDialog(hDlg, IDCANCEL);
         return TRUE;
      }
   }
   return FALSE; // 메세지 처리를 안한경우..
}

LRESULT CALLBACK WndProc( HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam){
   static DATA data= {TEXT("홍길동"), 20 };
   switch( msg ) {
   
   case WM_APPLY: // Dialog가 보내는 메세지
   {
      TCHAR buf[128];
      wsprintf(buf, TEXT("%s / %d"), data.str, data.num);
      SetWindowText(hwnd, buf);
   }
   return 0;
   
   case WM_LBUTTONDOWN: {
   if ( g_hDlg == 0)
   {
      // 모달리스 만들기.
      g_hDlg = CreateDialogParam( GetModuleHandle(0),// hinstance
      MAKEINTRESOURCE(IDD_DIALOG1),
      hwnd, // 부모
      DlgProc, // 메세지 함수.
      (LPARAM)&data);
      ShowWindow( g_hDlg, SW_SHOW );
   }
   else
   SetFocus( g_hDlg );//이미 만들어진 경우 focus이동
}
return 0;

적용 버튼 클릭시 대화상자가 종료되지 않고 타이틀바의 정보를 갱신시키는 것을 확인할 수 있습니다.

 

대화상자 기반 윈도우 프로그램

WinMain에서 윈도우 창을 만들지 않고 대화상자로 메인 윈도우의 역할을 수행할 수 있습니다.

BOOL CALLBACK DlgProc( HWND hDlg, UINT msg, WPARAM wParam, LPARAM lParam){
   switch (msg)
   {
      case WM_INITDIALOG: { }
      return TRUE;
      
      case WM_COMMAND:
      switch( LOWORD( wParam ) )
      {
      case IDCANCEL: EndDialog(hDlg, IDCANCEL); return 0;
      }
      return TRUE;
   }
   return FALSE;
}

int WINAPI WinMain(HINSTANCE hInst, HINSTANCE , PSTR lpCmdLine, int nShowCmd){
   UINT ret = DialogBox(hInst,// instance
   MAKEINTRESOURCE(IDD_DIALOG1), // 다이얼로그 선택
   0, // 부모 윈도우
   DlgProc); // Proc
   return 0;
}

 

 

728x90
반응형
  • 네이버 블러그 공유하기
  • 네이버 밴드에 공유하기
  • 페이스북 공유하기
  • 카카오스토리 공유하기