본문 바로가기

API

컨트롤과의 통신

컨트롤의 값 읽기

1. 핸들과 ID
차일드 컨트롤의 ID를 알고 있으면
HWND GetDlgItem(HWND hDlg, int nIDDlgItem);
함수로 이 컨트롤의 윈도우 핸들을 구할 수 있다.

반대로 컨트롤 핸들을 알고 있으면
HWND GetDlgCtrlID(HWND hwndCtl);
함수로 ID를 알 수 있다.

컨트롤은 윈도우이며 따라서 윈도우를 관리하기 위해서는 핸들이 필요하다. 그런데 핸들이라는 것은 그 특성상 운영체제가 일방적으로 발급하는 것이기 때문에 번호의 연속성이 없으며 그러다 보니 반복적인 처리에는 사용할 수 없다는 문제가 있다.

이 두 호출문을 합친 함수가 제공되는데 바로 다음 함수이다. 부모 대화상자의 핸들과 컨트롤의 ID만으로 편리하게 메시지를 보낼 수 있다.
LONG SendDlgItemMessage(HWND hDlg, int nID, UNIT Msg, WPARAM wParam, LPARAM lParam);


2. 정수와 문자열
대화상자와 컨트롤간에 교환할 수 있는 정보의 종류는 크게 문자열과 정수형 두가지가 있다.
문자열을 읽는 함수
UNIT GetDlgItemText(HWND hDlg, int nID, LPTSTR lpString, int nMaxCount);

문자열을 출력하는 함수
BOOL SetDlgItemText(HWND hDlg, int nID, LPCTSTR lpString);
첫 번째 인수는 대화상자의 윈도우 핸들이며, 두 번째 인수는 컨트롤 ID, 세 번째는 문자열, 네 번째는 버퍼의 길이이다.

정수형을 읽는 함수
UNIT GetDlgItemInt(HWND hDlg, int nID, BOOL *lpTranslated, BOOL bSigned;

문자열을 출력하는 함수
BOOL SetDlgItemInt(HWND hDlg, int nID, UINT uValue, BOOL bSigned);
첫 번째, 두 번째 인수는 문자열의 경우와 동일하며, GetDlgItemInt는 해당 컨트롤에 입력된 정수값을 읽어 리턴하되 네 번째 인수 bSigned가 TRUE일 경우는 부호있는 정수값을 읽고 FALSE일 경우는 부호를 무시하고 무조건 양수로 읽는다.
컨트롤로부터 정수형값을 읽어들일 때는 항상 에러가 발생할 소지가 있다. 예를 들어 에디트에 입력된 정수를 읽어들일 때 에디트에 숫자 이외의 문자가 있거나 숫자가 너무 클 경우 등이다. 이럴 경우 GetDlgItemInt는 세 번째 인수로 지정된 BOOL형 포인터에 에러가 있었는지 없었는지를 대입한다.
에러 검사를 할 필요가 없을 때는 세 번째 인수로 NULL값을 전달한다.


나이값을 표현하는 Age변수의 값을 IDC_EDIT이라는 에디트 컨트롤에 출력한다면 다음과 같이 코드를 작성한다.

int Age = 0;

BOOL OnInitDialog(HWND hDlg, WPARAM wParam, LPARAM lParam)
{
  SetDlgItemInt(hDlg,IDC_EDIT1,Age,FALSE);
  return TRUE;
}

BOOL OnDlgCommand(HWND hDlg, WPARAM wParam, LPARAM lParam)
{
  switch(LOWORD(wParam))
  {
    case IDOK:
      Age=GetDlgItemInt(hDlg,IDC_EDIT1,NULL,FALSE);
      EndDialog(hDlg,IDOK);
      break;
    case IDCANCEL:
      EndDialog(hDlg,IDCANCEL);
      break;
  }
  
  return TRUE;
}

실행시



위 처럼 Age에 값을 입력을 하고 Cancel버튼을 누르면 값이 저장이 되지 않아 다시 실행시키면 입력한 값이 출력되지 않고 초기에 입력되있던 값이 나온다. 물론 OK버튼을 누른다면 저장이되 다시 실행시키면 입력한 값으로 출력된다.


3. 논리형
정수와 문자열 외에도 BOOL형과 열거형도 대화상자를 통해 입력받을 수 있는데 두 값 중 하나를 표현하는 BOOL형은 체크 박스로 표시하는 것이 적합하며 여러가지 값 중 하나를 선택받는 열거형은 라디오 버튼이나 리스트 박스를 사용한다. 체크 박스나 라디오 버튼 등에 값을 대입하고 다시 읽어들이는 함수는 다음과 같다.

BOOL CheckDlgButton(HWND hDlg, int nIDButton, UINT uCheck);
UINT IsDlgButton(HWND hDlg, int nIDButton);

CheckDlgButton함수는 부모 윈도우의 핸들과 버튼의 ID, 그리고 원하는 체크 상태를 인수로 전달하면 버튼의 체크 상태를 변경한다.
예를 들어 bBold라는 변수의 값을 IDC_BOLD라는 체크 박스에 표시하고 싶다면 다음 코드를 사용한다.

BOOL CheckDlgButton(hDlg, IDC_BOLD, bBold? BST_CHECKED:BST_UNCHECKED);

bBold가 TRUE이면 IDC_BOLD 체크 박스가 체크될 것이고 그렇지 않다면 체크되지 않을 것이다. BST_CHECKED의 실제값이 1이고 BST_UNCHECKED의 실제값이 0으로 정의 되어 있으므로 사실? 이하의 코드는 꼭 필요치 않다. bBold 변수값을 그대로 체크 상태값으로 쓸 수 있으나 체크 박스에 설정된 상태를 이 변수로 다시 읽어들이는 코드는 다음과 같다.

bBold = IsDlgButtonChecked(hDlg,IDC_BOLD)==BST_CHECKED);

사용자가 IDC_BOLD 체크 박스를 선택해 놓았으면 bBold는 TRUE가 될 것이고 그렇기 않다면 FALSE가 될 것이다. 이 경우도 IsDlgButtonChecked의 리턴값을 bBlold에 바로 대입해도 동일한 코드이다. 버튼의 체크 상태를 설정하고 조사하는 두 함수는 사실 SendMessage의 변형이다. 위 두 함수는 다음 호출문과 동일하다.

SendMessage(GetDlgItem(hDlg,nDlgButton),BM_SETCHECK,uCheck,0);
SendMessage(GetDlgItem(hDlg,nDlgButton),BM_GETCHECK,0,0);

BM_SETCHECK, BM_GETCHECK 메시지를 보내면 버튼의 체크 상태를 변경 및 조사할 수 있다.
그러나 SendMessage 호출문은 ID가 아닌 윈도우 핸들을 요구하고 보내는 메시지의 이름도 써야 하므로 번거롭다. 좀 더 간단한 형식을 쓴다면 다음과 같이 쓸 수도 있다.

SendDlgItemMessage(hDlg,nIDButton,BM_SETCHECK,uCheck,0);
SendDlgItemMessage(hDlg,nIDButton,BM_GETCHECK,0,0);

역시 똑같은 문장이지만 CheckDlgButton보다는 타수가 더 많고 코드가 길어질 뿐만 아니라 사용하기도 불편하다. 함수 이름에 Dlg가 있지만 꼭 대화상자에서만 쓰는 것은 아니고 일반 윈도우의 차일드에 대해서도 사용할 수 있다.


InfoDlg

대화상자를 통해 사용자에게 현재 설정된 값을 보여주고 또한 사용자가 대화상자를 통해 값을 변경할 수 있도록 하는 예제

HWND hWndMain;
int x;
int y;
TCHAR str[128];

LRESULT OnCreate(HWND hWnd, WPARAM wParam, LPARAM lParam)
{
  hWndMain = hWnd;
  x=100;
  y=100;
  lstrcpy(str,TEXT("String"));
  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,MainDlgProc)==IDOK)
    InvalidateRect(hWnd,NULL,TRUE);

  return 0;
}

LRESULT OnPaint(HWND hWnd, WPARAM wParam, LPARAM lParam)
{
  HDC hdc;
  PAINTSTRUCT ps;
  
  hdc=BeginPaint(hWnd, &ps);
  TextOut(hdc,x,y,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)
{
  SetDlgItemText(hDlg,IDC_STR,str);
  SetDlgItemInt(hDlg,IDC_X,x,FALSE);
  SetDlgItemInt(hDlg,IDC_Y,y,FALSE);
  return TRUE;
}

BOOL OnDlgCommand(HWND hDlg, WPARAM wParam, LPARAM lParam)
{
  switch(LOWORD(wParam))
  {
    case IDOK:
      GetDlgItemText(hDlg,IDC_STR,str,128);
      x=GetDlgItemInt(hDlg,IDC_X,NULL,FALSE);
      y=GetDlgItemInt(hDlg,IDC_Y,NULL,FALSE);
      EndDialog(hDlg,IDOK);
      break;
    case IDCANCEL:
      EndDialog(hDlg,IDCANCEL);
      break;
  }
  
  return TRUE;
}


실행하면(100,100)좌표에 String이라는 문자열이 출력되어 있다.



마우스 왼쪽 버튼을 눌러 대화상자를 호출하고 문자열이나 좌표를 변경한 후 OK버튼을 누르면 변경된 좌표에 변경된 문자열이 출력된다.


'API' 카테고리의 다른 글

컨트롤(리스트,콤보 박스)  (0) 2011.09.23
컨트롤(에디트)  (0) 2011.09.23
컨트롤(라디오)  (0) 2011.09.21
컨트롤(체크박스)  (0) 2011.09.20
컨트롤(버튼)  (0) 2011.09.19