< Dialog Bar 사용하기 >

project name : Dlgbar - SDI - 나머지는 모두 디폴트로 적용

Project - Add To Project - Component and Controls...

여기서 Developer Studio Components 선택 - Dialog bar 선택 - insert를 누른다.

Dialog bar name : Dialog Bar,

Member variable name : m_wndDlgBar 로 정했다. 물론 마음대로 고쳐도 된다.

아래쪽의 라디오 버튼은 원하는 대로 선택하고, 그 밑 체크박스는 둘다 체크된 상태로 두자.

MainFrm.cpp 파일을 열어보면 중간쯤에서 다음부분을 볼 수 있다.

 

int CMainFrame::OnCreate(LPCREATESTRUCT lpCreateStruct)
{
    ..........
        // TODO: Add a menu item that will toggle the visibility of the
        // dialog bar named "My Dialog Bar":
        //   1. In ResourceView, open the menu resource that is used by
        //      the CMainFrame class
        //   2. Select the View submenu
        //   3. Double-click on the blank item at the bottom of the submenu
        //   4. Assign the new item an ID: CG_ID_VIEW_MYDIALOGBAR
        //   5. Assign the item a Caption: My Dialog Bar

        // TODO: Change the value of CG_ID_VIEW_MYDIALOGBAR to an appropriate value:
        //   1. Open the file resource.h
        // CG: The following block was inserted by the 'Dialog Bar' component
        {
                // Initialize dialog bar m_wndDlgBar
                if (!m_wndDlgBar.Create(this, CG_IDD_MYDIALOGBAR, CBRS_RIGHT |
 CBRS_TOOLTIPS | CBRS_FLYBY | CBRS_HIDE_INPLACE, CG_ID_VIEW_MYDIALOGBAR))
     ......... 

주석에서 위의 TODO 부분은 메뉴에서 다이얼로그바를 보였다가 감추었다가 하는 명령어를 추가하는 것을 설명한 것이고, 아래쪽 TODO 부분은 다이얼로그바 ID를 원하는 대로 바꾸는 것을 설명한 것이다.

① 우선 위의 코드에서 밑줄친 부분을 원하는 ID 로 바꾼다.
- 여기서는 IDD_MYDLGBAR 로 정했다.

② 다음으로 Resources 탭에서 Dialog 부분을 보면 CG_IDD_MYDIALOGBAR 라는 ID가 보이는데 이것도 IDD_MYDLGBAR 로 바꾸자. 이렇게 해서 다이얼로그바 ID를 원하는 대로 바꿀 수 있다.

 

다음으로 메뉴에 다이얼로그바를 보였다 감추었다하는 코드를 추가해 보자.

① String Table에서 ID를 보면 CG_ID_VIEW_DIALOGBAR 가 있는데 이것을 ID_VIEW_DIALOG_BAR 로 바꾼다.

② 다음으로 Menu - IDR_MAINFRAME - '보기(V)' 에 캡션은 '다이얼로그 바' , ID는 위에서 바꾼대로 ID_VIEW_DIALOG_BAR 인 메뉴를 하나 추가한다.

③ 다음 코드에서 밑줄친 부분을 ID_VIEW_DIALOG_BAR 로 바꾼다.

 
/////////////////////////////////////////////////////////////////////////////
// CMainFrame

IMPLEMENT_DYNCREATE(CMainFrame, CFrameWnd)

BEGIN_MESSAGE_MAP(CMainFrame, CFrameWnd)
        ON_COMMAND_EX(CG_ID_VIEW_DIALOGBAR, OnBarCheck)
        ON_UPDATE_COMMAND_UI(CG_ID_VIEW_DIALOGBAR, OnUpdateControlBarMenu)
        //{{AFX_MSG_MAP(CMainFrame)

④ 다음 코드의 밑줄친 부분도 ID_VIEW_DIALOG_BAR 로 고친다.

int CMainFrame::OnCreate(LPCREATESTRUCT lpCreateStruct)
{       
       ................
                // Initialize dialog bar m_wndDialogBar
                if (!m_wndDialogBar.Create(this, IDD_MYDLGBAR, CBRS_TOP |
                      CBRS_TOOLTIPS | CBRS_FLYBY | CBRS_HIDE_INPLACE,
                    CG_ID_VIEW_DIALOGBAR))
       ................
                        

note) 위에서 설명한 것처럼 ID를 바꾸지 않고 있는 그대로 사용해도 무방하지만 프로그램
의 이해를 돕기위해 ID를 보다 의미있는 단어로 바꾸어준 것이다.

 

- 다이얼로그바 이벤트 얻기

위와 같이 다이얼로그바를 만든 뒤 클래스 위저드를 실행시켜 보면 5.0 버전에서는 콘트롤의 메시지가 나타나지 않습니다. (6.0 버전에서는 메시지가 나타납니다만.)

그래서 클래스 위저드로는 다양한 이벤트를 가로채서 실행하는 함수를 만들수가 없습니다. 그 이유는 클래스 위저드에 등록되어 있는 클래스가 없기 때문입니다. 다이얼로그바를 만들면서 보면 다이얼로그바에 관계된 코드는 모두 MainFrm.cpp 안에 기술되는 것을 볼 수 있습니다.

다이얼로그바는 클래스 위저드로 등록하여 만든 것이 아니고 대화상자를 만든다음 이 대화상자를 CDialog 멤버의 변수로 연결한 것이기 때문입니다. 그렇다고 이벤트를 만들지 못하는 것이 아닙니다. MFC의 매크로에는 이런 문제를 해결하기 위해서 ON_CBN, ON_LBN, ON_EN, ON_BN 계열의 메시지 맵핑 매크로를 만들어 두었습니다. ON_CBN 은 콤보박스에서 이벤트가 발생하였을 때의 메세지 매크로이며 ON_LBN은 리스트 박스에서, ON_EN은 에디트 박스에서, ON_BN은 버튼에서입니다.

① 다이얼로그바에 다음의 콘트롤들을 추가합니다. 라디오 버튼은 ID와 tap order가 반드시 연속적이어야 합니다. 그 이유는 아래 ②번의 ON_CONTROL_RANGE와 관계가 있습니다.

에디트 박스 - ID : IDC_EDIT1
버튼 - ID : IDC_BUTTON1
콤보 박스 - ID : IDC_COMBO1
라디오 버튼 3개 - ID : IDC_RADIO1 ~ IDC_RADIO3
체크 박스 - ID : IDC_CHECK1

② MainFrm.cpp 파일에서 다음을 추가합니다.

BEGIN_MESSAGE_MAP(CMainFrame, CFrameWnd)
        ON_COMMAND_EX(ID_VIEW_DIALOG_BAR, OnBarCheck)
        ON_UPDATE_COMMAND_UI(ID_VIEW_DIALOG_BAR, OnUpdateControlBarMenu)
        //{{AFX_MSG_MAP(CMainFrame)
                // NOTE - the ClassWizard will add and remove mapping macros here.
                //    DO NOT EDIT what you see in these blocks of generated code !
        ON_WM_CREATE()
        ON_BN_CLICKED(IDC_BUTTON1, OnButton1)   // <-추가 : 버튼 클릭
        ON_CBN_SELCHANGE(IDC_COMBO1, OnComboChange)    //<-추가 : 콤보박스 
        ON_BN_CLICKED(IDC_CHECK1, OnCheck1)                // <-추가 : 체크박스
        ON_CONTROL_RANGE(BN_CLICKED, IDC_RADIO1, IDC_RADIO3, OnRadioButton1)
                                        // <-추가 : 라디오 버튼

        //}}AFX_MSG_MAP
END_MESSAGE_MAP()  

④ MainFrm.h 에도 다음 내용을 추가합니다.

// Generated message map functions
protected:
        CDialogBar m_wndDialogBar;
        //{{AFX_MSG(CMainFrame)
        afx_msg int OnCreate(LPCREATESTRUCT lpCreateStruct);
        afx_msg void OnButton1();     // <-추가 : 버튼의 클릭
        afx_msg void OnComboChange();    //<-추가 : 콤보박스
        afx_msg void OnCheck1();           // <-추가 : 체크박스
        afx_msg void OnRadioButton1();     // <-추가 : 라디오 버튼
 
        // NOTE - the ClassWizard will add and remove member functions here.
        //    DO NOT EDIT what you see in these blocks of generated code!
        //}}AFX_MSG
        DECLARE_MESSAGE_MAP()

⑤ MainFrm.cpp 에 핸들러를 추가합니다.

/////////////////////////////////////////////////////////////////////////////
// CMainFrame message handlers

void CMainFrame::OnButton1()    // 버튼의 핸들러
{
        CEdit *pWnd = (CEdit *)m_wndDialogBar.GetDlgItem(IDC_EDIT1);
        // 다이얼로그바 안의 에디트 박스의 포인터 얻기 

        CString str;
        
        pWnd->GetWindowText(str); // 에디트 박스의 내용 읽어오기
        AfxMessageBox(str);
}
void CMainFrame::OnComboChange()  // 콤보 박스의 핸들러
{
        CComboBox *pWnd = (CComboBox *)m_wndDialogBar.GetDlgItem(IDC_COMBO1);
        int num = pWnd->GetCurSel();
        
        CString str;

        pWnd->GetLBText(num, str);
        AfxMessageBox(str);
}
void CMainFrame::OnCheck1()  // 체크 박스의 핸들러
{
        CButton *pCheck = (CButton *)m_wndDialogBar.GetDlgItem(IDC_CHECK1);
        CButton *pRadio = (CButton *)m_wndDialogBar.GetDlgItem(IDC_RADIO1); 
        
        // pCheck->SetCheck(pWnd->GetCheck() ? BST_UNCHECKED : BST_CHECKED);
        // 체크표시를 toggle 하는  코드
        // 체크박스 property의 Styles - auto 가 체크되어 있다면 위 코드는 필요없다.
        
        // 라디오버튼을 Enable/Disable 시키는 부분 - CWnd::EnableWindow(BOOL) 사용
        if(pCheck->GetCheck()) pRadio->EnableWindow(false);
        else pRadio->EnableWindow(true);   
}
void CMainFrame::OnRadioButton1()  // 라디오 버튼의 핸들러
{
        CButton *pRadio1 = (CButton *)m_wndDialogBar.GetDlgItem(IDC_RADIO1);
        CButton *pRadio2 = (CButton *)m_wndDialogBar.GetDlgItem(IDC_RADIO2);
        CButton *pRadio3 = (CButton *)m_wndDialogBar.GetDlgItem(IDC_RADIO3);
        
        // pRadio1->SetCheck(BST_CHECKED);
        // pRadio2->SetCheck(BST_UNCHECKED);
        // pRadio3->SetCheck(BST_UNCHECKED);
        // 라디오 버튼 선택표시 하는 부분       
        // 라디오 버튼 property의 Styles - auto 가 체크되어 있다면 위 코드는 필요없다 

        if(pRadio1->GetCheck()) AfxMessageBox(CString("라디오 1"));
        else if(pRadio2->GetCheck()) AfxMessageBox(CString("라디오 2"));
        else AfxMessageBox(CString("라디오 3"));
}

note 1)

Button 컨트롤에는 Push Button, Check Box, Radio Button, Group Box의 4가지가 있다.
그러므로 그러한 컨트롤들도 모두 Button 컨트롤에 쓰이는 매크로를 사용하여 조작한다.
MainFrame의 메시지 맵에서 라디오버튼 부분을 보자.

ON_CONTROL_RANGE(BN_CLICKED, IDC_RADIO1, IDC_RADIO3, OnRadioButton1)

이 것은 다음을 줄여 쓴 것이다.

ON_BN_CLICKED(IDC_RADIO1, OnRadioButton1)
ON_BN_CLICKED(IDC_RADIO2, OnRadioButton1)
ON_BN_CLICKED(IDC_RADIO3, OnRadioButton1)

ON_CONTROL_RANGE()는 같은 종류의 메시지를 범위로 묶어 한꺼번에 처리할 수 있도록 MFC 3.x부터 추가된 매크로이다. 이 매크로를 쓰려면 컨트롤들의 ID와 tap order가 연속적이어야 한다.

순서가 맞지 않다면 tap order는 CTRL-D를 눌러 고칠수 있고, ID는 Resource.h를 열어 원하는 ID에 배당된 숫자를 연속적으로 고치면 된다.

 

note 2)

자기가 쓰는 컨트롤에 원하는 기능의 함수가 없다면 CWnd 의 멤버함수를 찾아보자.

다음은 CWnd 멤버함수의 일부이다.

EnableWindow()
: 윈도우를 사용가능하게 하거나 사용 금지시킨다. 사용이 금지된 윈도우는 마우스나 키보드 등 일체의 입력을 받아들일 수 없다. 주로 버튼 등의 차일드 윈도우에 사용된다.

GetClientRect()
: 윈도우의 작업영역을 구한다. 좌상단은 항상 (0,0)이며 우하단은 작업영역의 크기를 나타낸다.

GetWindowRect()
: 윈도우가 차지하고 있는 영역의 화면좌표를 구한다. 이 영역에는 작업영역뿐만 아니라 타이틀 바, 스크롤 바, 경계선까지 모두 포함된다.

GetWindowText() / SetWindowText()
: 윈도우의 타이틀 바에 출력되어 있는 캡션을 구한다. / 변경한다. 컨트롤일 경우 컨트롤의 텍스트 문자열이 읽혀진다. / 변경된다.

 

note 3)

MFC 4.x에는 다음과 같은 매크로들이 있다. (일반적인 공통 매크로 제외)

ON_COMMAND()

ON_COMMAND_RANGE()

ON_COMMAND_EX()

ON_COMMAND_EX_RANGE()

ON_UPDATE_COMMAND_UI()

ON_UPDATE_COMMAND_UI_RANGE()

ON_UPDATE_COMMAND_LI_REFLECT()

ON_NOTIFY()

ON_NOTIFY_RANGE()

ON_NOTIFY_EX()

ON_NOTIFY_EX_RANGE()

ON_NOTIFY_REFLECT()

ON_NOTIFY_REFLECT_EX()

ON_CONTROL()

ON_CONTROL_RANGE()

ON_CONTROL_REFLECT()

ON_CONTROL_REFLECT_EX()

ON_WM_CTLCOLOR_REFLECT()

ON_WM_DRAWITEM_REFLECT()

ON_WM_MEASUREITEM_REFLECT()

ON_WM_DELETEITEM_REFLECT()

ON_WM_CHARTOITEM_REFLECT()

ON_WM_VKEYTOITEM_REFLECT()

ON_WM_HSCROLL_REFLECT()

ON_WM_VSCROLL_REFLECT()

ON_WM_PARENTNOTIFY_REFLECT()