Radio Button 이란?
Check Box와 비슷하지만 약간은 다른 선택형 컨트롤 입니다.
Check Box는 일반적으로 다수의 Check Box를 선택할 수 있지만,
Radio Button은 일반적으로 한 Group 안에서 하나의 선택만 할 수 있도록 유도하는 선택형 컨트롤 입니다.
Radio Button도 Check Box와 마찬가지로 Button 입니다.
Radio Button 생성
"도구 상자" 에서 "Radio Button"을 선택하여 생성합니다.
Radio Button은 "Group" 설정을 해야합니다.
Group 설정에는 다음과 같은 요구 조건이 필요합니다.
- Group 의 가장 첫 번째 Radio Button 컨트롤은 "Group 속성"이 "True"
- 한 Group에 있는 Radio Button 컨트롤의 ID는 "순차적"
1. Group 의 가장 첫 번째 Radio Button 컨트롤은 "Group 속성"이 "True"
먼저 첫 번째 요소인 "첫 번째 Radio Button 컨트롤의 Group 속성이 True" 를 봅시다.
속성에서 "그룹(Group)" 이라는 것이 존재하는데 해당 그룹의 첫 번째 컨트롤은 이 값이 True여야 합니다.
(해당 그룹의 시작을 알리는 겁니다. 즉, 컨트롤 ID가 순차적으로 흐르다가 어떤 특정 컨트롤 ID의 Group 요소가 true를 만나게 되면 그 전까지의 컨트롤 까지를 하나의 그룹으로 보게 됩니다.)
이런 식으로 Group을 짜게 되는 것이지요.
2. 한 Group에 있는 Radio Button 컨트롤의 ID는 "순차적"
두 번째는 컨트롤의 ID는 순차적이어야 한다는 것입니다.
우리가 생성한 컨트롤에는 ID라는 것이 부여됩니다.
이 ID는 define으로 정의된 숫자값으로 "Resource.h"에 정의되어 있습니다.
//{{NO_DEPENDENCIES}}
// Microsoft Visual C++에서 생성한 포함 파일입니다.
// MFCTest.rc에서 사용되고 있습니다.
//
#define IDD_MFCTEST_DIALOG 102
#define IDR_MAINFRAME 128
#define IDC_RADIO1 1005
#define IDC_RADIO2 1006
#define IDC_RADIO3 1007
#define IDC_RADIO4 1008
// Next default values for new objects
//
#ifdef APSTUDIO_INVOKED
#ifndef APSTUDIO_READONLY_SYMBOLS
#define _APS_NEXT_RESOURCE_VALUE 130
#define _APS_NEXT_COMMAND_VALUE 32771
#define _APS_NEXT_CONTROL_VALUE 1009
#define _APS_NEXT_SYMED_VALUE 101
#endif
#endif
여기서 보면 제가 생성한 Radio Button 컨트롤의 ID는 "1005 ~ 1008" 으로 일정하게 생성이 되었습니다.
(여담으로 다음에 생성될 컨트롤은 1009번(_APS_NEXT_CONTROL_VALUE)이 됩니다.)
만약에 중간에 컨트롤이 하나가 끼어서
#define IDD_MFCTEST_DIALOG 102
#define IDR_MAINFRAME 128
#define IDC_RADIO1 1005
#define IDC_RADIO2 1006
#define IDC_EDIT1 1007 // <-- 끼어버린 컨트롤
#define IDC_RADIO3 1008
#define IDC_RADIO4 1009
이렇게 되어버렸다고 합시다.
이렇게 되면 Radio1 ~ Radio3 까지의 연결이 중간에 끊겨버린 것이지요.
해결 방법은 "Resource.h" 파일을 직접 수정하는 것입니다.
#define IDD_MFCTEST_DIALOG 102
#define IDR_MAINFRAME 128
#define IDC_RADIO1 1005
#define IDC_RADIO2 1006
#define IDC_RADIO3 1007
#define IDC_EDIT1 1008 // <-- Radio 3번과 번호 스왑
#define IDC_RADIO4 1009
하지만 이렇게 직접 리소스 파일을 수정할 때는 ID가 중복되지 않게 해야합니다.
잘못 ID가 꼬이거나 중복된 번호가 들어가게 되면 컨트롤이 꼬이기 때문이죠.
Radio Button 사용
Radio Button을 사용하기 위해서는 보통 "ON_CONTROL_RANGE" 라는 것을 사용합니다.
Check Box나 일반적인 Button의 경우에는 각각의 컨트롤에 "ON_CLICKED"와 같은 이벤트를 이용하여 관리하였다면
Radio Button의 경우에는 그룹으로 관리를 하기 때문에 각 그룹별로 하나의 Range로 관리하게 됩니다.
ON_CONTROL_RANGE 에는 4개의 인자가 들어가게 됩니다.
항목 | 설명 |
wNotifyCode | 반응하게 되는 이벤트의 ID (예: BN_CLICKED) |
id | 컨트롤 할 그룹의 시작 컨트롤 ID |
idLast | 컨트롤 할 그룹의 끝 컨트롤 ID |
memberFxn | 컨트롤 할 때 사용할 함수 (메시지 핸들러 함수) |
이때 메시지 핸들러 함수는
UINT를 매개변수로 받은 void형 함수입니다.
그럼 한 번 사용해봅시다.
이렇게 두 개의 그룹으로 쪼갰습니다.
각 그룹 옆에는 선택한 결과를 표출하는 Static 을 각각 1개씩 두었습니다.
먼저 각 그룹에서 사용할 메시지 핸들러 함수를 각각 만들어 주겠습니다.
public:
// Radio1 ~ Radio3 에서 사용할 메시지 핸들러 함수
afx_msg void OnRangeRadioGroup1(UINT uID);
// Radio4 ~ Radio5 에서 사용할 메시지 핸들러 함수
afx_msg void OnRangeRadioGroup2(UINT uID);
먼저 헤더에 두 함수를 선언한 후에
/**
Radio1 ~ Radio3 에서 사용할 메시지 핸들러 함수
*/
void CMFCTestDlg::OnRangeRadioGroup1(UINT uID)
{
switch (uID)
{
case IDC_RADIO1:
SetDlgItemText(IDC_STATIC_RES1, _T("Radio 1"));
break;
case IDC_RADIO2:
SetDlgItemText(IDC_STATIC_RES1, _T("Radio 2"));
break;
case IDC_RADIO3:
SetDlgItemText(IDC_STATIC_RES1, _T("Radio 3"));
break;
}
}
/**
Radio4 ~ Radio5 에서 사용할 메시지 핸들러 함수
*/
void CMFCTestDlg::OnRangeRadioGroup2(UINT uID)
{
switch (uID)
{
case IDC_RADIO4:
SetDlgItemText(IDC_STATIC_RES2, _T("Radio 4"));
break;
case IDC_RADIO5:
SetDlgItemText(IDC_STATIC_RES2, _T("Radio 5"));
break;
}
}
이렇게 각각의 함수를 선언해줍니다.
BEGIN_MESSAGE_MAP(CMFCTestDlg, CDialogEx)
ON_WM_PAINT()
ON_WM_QUERYDRAGICON()
ON_CONTROL_RANGE(BN_CLICKED, IDC_RADIO4, IDC_RADIO5, &CMFCTestDlg::OnRangeRadioGroup2)
ON_CONTROL_RANGE(BN_CLICKED, IDC_RADIO1, IDC_RADIO3, &CMFCTestDlg::OnRangeRadioGroup1)
END_MESSAGE_MAP()
그리고 이렇게 메시지 맵에 두 함수를 연결해 줍니다.
그리고 한 가지 더 해야 할 부분이 있는데
BOOL CMFCTestDlg::OnInitDialog()
{
CDialogEx::OnInitDialog();
SetIcon(m_hIcon, TRUE);
SetIcon(m_hIcon, FALSE);
((CButton*)GetDlgItem(IDC_RADIO1))->SetCheck(TRUE); // <---
((CButton*)GetDlgItem(IDC_RADIO4))->SetCheck(TRUE); // <---
return TRUE;
}
OnInitDialog 함수에서 초기 선택 값을 설정합니다.
실행하여 봅시다.
초기값을 설정하는 이유?
이유가 있는데요.
우리는 Radio 버튼을 "변수"로 선언하여 사용하지 않았습니다.
하지만 이렇게 변수 형식(int)으로 사용하는 방법이 있는데 이 방법으로 하면 초기값이 정해지게 됩니다.
그런데 위와 같이 변수 형식으로 하지않고 사용하게 되면 다음과 같은 일이 일어납니다.
먼저 지금까지 잘 따라 했다면 프로그램 UI의 Tab 순서는 다음과 같이 됩니다.
Ctrl + D 를 누르면 Tab 순서를 볼수 있게 됩니다.
여기서 Radio 버튼에 첫번째 Tab이 부여가 되는데 이 상태에서 Radio1과 연결된 메시지 핸들러 함수에 디버깅을 찍어 봅시다.
Switch 문 가장 처음에 디버깅을 찍고 F5를 눌러서 실행을 하면
프로그램을 시작하자마자 UI가 뜨지도 않았는데 바로 해당 메시지 핸들러 함수로 들어가게 됩니다.
원래 권장하지는 않지만 저 메시지 핸들러 함수에 AfxMessageBox와 같은 팝업기반의 동작을 넣게 된다면 바로 그 명령을 수행하게 되어버리는 것이지요.
하지만 OnInitDialog에서 미리 초기값을 설정하게 되면 바로 디버깅이 찍히지 않게 됩니다.
(어떠한 이유 때문인지는 잘 모르겠습니다...)
Radio Button의 일반 Button 형태 (Push-Like)
Radio Button도 Button 기반이기 때문에 버튼의 모양으로 사용할 수 있습니다.
속성 중 "누름과 유사(Push-Like)" 입니다.
이렇게 일반 버튼처럼 변경됩니다.
'Study > MFC' 카테고리의 다른 글
[MFC/Win32 API] 파일의 생성 시간, 접근 시간, 쓰기 시간 (2) | 2022.10.15 |
---|---|
[MFC] ListBox 컨트롤 (리스트박스) (0) | 2022.10.13 |
[MFC] Check Box 컨트롤 (체크 박스) (0) | 2022.09.03 |
[MFC] Combo Box 컨트롤 (콤보 박스) (0) | 2022.03.05 |
[MFC] Button 컨트롤 - 색상 변경 (0) | 2022.02.17 |