내장형 하드웨어/WINAPI

WINAPI - DlgCheck

동화다아아 2011. 9. 29. 14:56
- 대화상자를 통해 입력 받는 값이 BOOL 형과 열거인 예제
 → BOOL 형은 체크 박스로 표시하고 열거형은 라디오 박스로 표시하는데 값을 보여주고 다시 읽는 방법이 정수나 문자열과 다를 뿐 전체적인 논리는 비슷하다.
//main.cpp
#include<windows.h>

#include "MsgProc.h" // add

LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);
HINSTANCE g_hInst;
LPCTSTR lpszClass = TEXT("First");

// add
typedef struct MESSAGEMAP
{
  UINT iMessage;
  LRESULT (*lpfnMsgProc)(HWND, WPARAM, LPARAM);
}MESSAGEMAP;

//CALLBACKAboutDlgProc
typedef struct DLGMESSAGEMAP  
{
  UINT iMessage;
  BOOL (*lpfnMsgProc)(HWND, WPARAM, LPARAM);
}DLGMESSAGEMAP;


int APIENTRY WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpszCmdParam, int nCmdShow)
{
  HWND hWnd;
  MSG Message;
  WNDCLASS WndClass;
  g_hInst = hInstance;

  WndClass.cbClsExtra = 0;
  WndClass.cbWndExtra = 0;
  WndClass.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH);
  WndClass.hCursor = LoadCursor(NULL, IDC_ARROW);
  WndClass.hIcon = LoadIcon(NULL, IDI_APPLICATION);
  WndClass.hInstance = hInstance;
  WndClass.lpfnWndProc = WndProc;
  WndClass.lpszClassName = lpszClass;
  WndClass.lpszMenuName = NULL;
  WndClass.style = CS_HREDRAW | CS_VREDRAW;
  RegisterClass(&WndClass);

  hWnd = CreateWindow(lpszClass, lpszClass, WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, NULL, (HMENU)NULL, hInstance, NULL);;
  ShowWindow(hWnd, nCmdShow);

  while(GetMessage(&Message, NULL, 00))
  {
    TranslateMessage(&Message);
    DispatchMessage(&Message);
  }
  return (int)Message.wParam;

}
BOOL CALLBACK MajorDlgProc(HWND hDlg,UINT iMessage, WPARAM wParam, LPARAM lParam)
{
  int i;
  static DLGMESSAGEMAP DlgMessageMaps[] = {
  {WM_INITDIALOG, OnInitDialog},
  {WM_COMMAND, OnDlgCommand}    
  };


  for(i=0; i<sizeof(DlgMessageMaps)/sizeof(DlgMessageMaps[0]); ++i)
  {
  if(DlgMessageMaps[i].iMessage == iMessage)
    return (*DlgMessageMaps[i].lpfnMsgProc)(hDlg, wParam, lParam);
  }

  return FALSE;
}

LRESULT CALLBACK WndProc(HWND hWnd, UINT iMessage, WPARAM wParam, LPARAM lParam)
{
  //add
  int i;
  static MESSAGEMAP MessageMaps[] = {
    {WM_CREATE, OnCreate},
    {WM_COMMAND, OnCommand},
    {WM_LBUTTONDOWN, OnLButtonDown},
    {WM_PAINT, OnPaint},
    {WM_DESTROY, OnDestroy}
  };

  for(i=0; i<sizeof(MessageMaps)/sizeof(MessageMaps[0]);++i)
  {
    if(MessageMaps[i].iMessage == iMessage)
    {
      return (*MessageMaps[i].lpfnMsgProc)(hWnd, wParam, lParam);
    }    
  }
  ///////////////////////////

  return(DefWindowProc(hWnd, iMessage, wParam, lParam)); 
}


//MsgProc.cpp
#include
 "MsgProc.h"

BOOL bMale;
TCHAR str[128];
enum tag_Major{MANAGE, KOREAN, ENGLISH, LAW}Major;
TCHAR *arMajor[] = {TEXT("경영학과"), TEXT("국문학과"), TEXT("영문학과"), TEXT("법학과")};

LRESULT OnCreate(HWND hWnd, WPARAM wParam, LPARAM lParam)
{
  bMale = TRUE;
  Major = KOREAN;
  return 0;
}
LRESULT OnCommand(HWND hWnd, WPARAM wParam, LPARAM lParam)
{
  return 0;
}
LRESULT OnLButtonDown(HWND hWnd, WPARAM wParam, LPARAM lParam)
{
  if(DialogBox(g_hInst, MAKEINTRESOURCE(IDD_DIALOG1), hWnd, MajorDlgProc) == IDOK)
  {
    InvalidateRect(hWnd, NULL, TRUE);
  }
  return 0;
}
LRESULT OnPaint(HWND hWnd, WPARAM wParam, LPARAM lParam)
{
  HDC hdc;
  PAINTSTRUCT ps;

  hdc = BeginPaint(hWnd, &ps);

  wsprintf(str, TEXT("성별 = %s"), bMale ? TEXT("남자"):TEXT("여자"));
  TextOut(hdc, 1010, str, lstrlen(str));
  wsprintf(str, TEXT("전공 = %s"), arMajor[Major]);
  TextOut(hdc, 1030, str, lstrlen(str));
  EndPaint(hWnd, &ps);
  return 0;
}
LRESULT OnDestroy(HWND hwnd, WPARAM wParam, LPARAM lParam)
{
  PostQuitMessage(0);
  return 0;
}

/////////////////////////////////////////////////////////////////////
BOOL OnInitDialog(HWND hDlg, WPARAM wParam, LPARAM lParam)
{
  CheckDlgButton(hDlg, IDC_MALE, bMale ? BST_CHECKED:BST_UNCHECKED);
  CheckRadioButton(hDlg, IDC_MAJOR1, IDC_MAJOR4, IDC_MAJOR1+Major);
  return TRUE;
}
BOOL OnDlgCommand(HWND hDlg, WPARAM wParam, LPARAM lParam)
{
  switch(LOWORD(wParam))
  {
  case IDOK:
    bMale = (IsDlgButtonChecked(hDlg, IDC_MALE)==BST_CHECKED);
    if(IsDlgButtonChecked(hDlg, IDC_MAJOR1)==BST_CHECKED)
    {
      Major = MANAGE;
    }
    if(IsDlgButtonChecked(hDlg, IDC_MAJOR2)==BST_CHECKED)
    {
      Major = KOREAN;
    }
    if(IsDlgButtonChecked(hDlg, IDC_MAJOR3)==BST_CHECKED)
    {
      Major = ENGLISH;
    }
    if(IsDlgButtonChecked(hDlg, IDC_MAJOR4)==BST_CHECKED)
    {
      Major = LAW;
    }
    EndDialog(hDlg, IDOK);
    return TRUE;
  case IDCANCEL:
    EndDialog(hDlg, IDCANCEL);
    return TRUE;
  }

  return FALSE;
}


 → 출력 결과


 → 출력 결과
 → 성별을 나타내는 bMale과 전공을 나타내는 열거형 Major 변수가 선언되어 있으며 WndProc에서는 이 값을 화면으로 출력하여 확인하기만 한다. 이 두 값을 대화상자로 보여주고 입력받기 위해 다음과 같은 대화 상자를 만들었다.

 → bMale 변수의 상태를 IDC_MALE 체크 박스에 표시하고 Major 변수의 값을 IDC_MAJOR1 ~ IDC_MAJOR4 사이의 라디오 버튼에 표시하면 될 것이다.
 → WM_INITDIALOG에서 CheckDlgButton으로 bMale 변수값에 따라 IDC_MALE 체크 박스의 상태를 체크 또는 비체크로 설정했다. 
 → 편집된 값을 다시 읽어올 때는 IsDlgButtonChecked 함수로 각 버튼의 체크 상태를 조사한다. 라디오 버튼 중 체크된 버튼을 구할 때는 모든 라디오 버튼에게 일일이 질문을 해서 체크된 버튼을 찾는 방법밖에 없다.
 → 이럴 때는 어떤 그룹에서 어떤 버튼이 선택되어 있는지 조사하는 다음과 같은 함수를 만들어 쓸 수도 있을 것이다.
int GetCheckedRadioButton(HWND hDlg, int First, int Last)
{
       int id;
       for(id = First; id<=Last ; ++id)
       {
              if(IsDlgButtonChecked(hDlg, id)==BST_CHECKED)
              {
                     return id;
              }
       }
       return -1;
}
→ 인수로 전달된 First ~ Last 까지 라디오 그룹의 범위만큼 루프를 돌며 각 버튼들에게 질문하여 체크된 버튼을 만나면 그 버튼의 id를 리턴하는 것이다. 이 함수를 쓴다면 다음 한 줄로 라디오 버튼에서 사용자가 선택한 옵션을 읽을 수 있다.

Major = tag_Major(GetCheckedRadioButton(hDlg, IDC_MAJOR1, IDC_MAJOR4)-IDC_MAJOR1);
→ API의  래퍼 라이브러리인 MFC에는 실제로 이 함수가 존재한다.
→ 이 함수의 예에서 볼수 있듯이 려러개의 컨트롤에 대해 루프를 돌리기 위해 핸들 외에도 사용자가 값을 통제할 수 있는 ID가 필요하다.
→ 단, 이런식의 루프를 돌리려면 라디오 버튼들이 반드시 연속적인 ID를 가지고 있어야 한다.