TN062: Windows 컨트롤에 대한 메시지 리플렉션

참고 항목

다음 기술 노트는 온라인 설명서에 먼저 포함되어 있었으므로 업데이트되지 않았습니다. 따라서 일부 절차 및 항목은 만료되거나 올바르지 않을 수 있습니다. 최신 정보를 보려면 온라인 설명서 색인에서 관심 있는 항목을 검색하는 것이 좋습니다.

이 기술 참고에서는 MFC 4.0의 새로운 기능인 메시지 리플렉션에 대해 설명합니다. 또한 메시지 리플렉션을 사용하는 간단한 재사용 가능한 컨트롤을 만들기 위한 지침도 포함되어 있습니다.

이 기술 참고 사항은 ActiveX 컨트롤(이전의 OLE 컨트롤)에 적용되므로 메시지 리플렉션에 대해 설명하지 않습니다. ActiveX 컨트롤: Windows 컨트롤 서브클래싱 문서를 참조하세요.

메시지 리플렉션이란?

Windows 컨트롤은 부모 창에 알림 메시지를 자주 보냅니다. 예를 들어 많은 컨트롤은 부모가 컨트롤의 배경을 그리기 위한 브러시를 제공할 수 있도록 컨트롤 색 알림 메시지(WM_CTLCOLOR 또는 변형 중 하나)를 부모에 보냅니다.

Windows 및 버전 4.0 이전의 MFC에서는 종종 대화 상자인 부모 창에서 이러한 메시지를 처리합니다. 즉, 메시지 처리를 위한 코드는 부모 창의 클래스에 있어야 하며 해당 메시지를 처리해야 하는 모든 클래스에서 중복되어야 합니다. 위의 경우 사용자 지정 배경이 있는 컨트롤을 원하는 모든 대화 상자에서 컨트롤 색 알림 메시지를 처리해야 합니다. 자체 배경색을 처리하는 컨트롤 클래스를 작성할 수 있는 경우 코드를 다시 사용하는 것이 훨씬 쉽습니다.

MFC 4.0에서는 이전 메커니즘이 계속 작동합니다. 부모 창에서 알림 메시지를 처리할 수 있습니다. 그러나 MFC 4.0은 자식 제어 창 또는 부모 창 또는 둘 다에서 이러한 알림 메시지를 처리할 수 있는 "메시지 리플렉션"이라는 기능을 제공하여 재사용을 용이하게 합니다. 이제 컨트롤 배경색 예제에서 부모에 의존하지 않고 반사된 WM_CTLCOLOR 메시지를 처리하여 자체 배경색을 설정하는 컨트롤 클래스를 작성할 수 있습니다. (메시지 리플렉션은 Windows가 아닌 MFC에 의해 구현되므로 메시지 리플렉션이 작동하려면 부모 창 클래스가 CWnd 파생되어야 합니다.)

이전 버전의 MFC는 소유자가 그린 목록 상자(WM_DRAWITEM 등)에 대한 메시지와 같은 몇 가지 메시지에 대한 가상 함수를 제공하여 메시지 리플렉션과 비슷한 작업을 수행했습니다. 새 메시지 리플렉션 메커니즘은 일반화되고 일관됩니다.

메시지 리플렉션은 4.0 이전 버전의 MFC용으로 작성된 코드와 이전 버전과 호환됩니다.

부모 창의 클래스에서 특정 메시지 또는 메시지 범위에 대한 처리기를 제공한 경우 사용자 고유의 처리기에서 기본 클래스 처리기 함수를 호출하지 않으면 동일한 메시지에 대해 반영된 메시지 처리기가 재정의됩니다. 예를 들어 대화 상자 클래스에서 WM_CTLCOLOR 처리하는 경우 처리는 반영된 모든 메시지 처리기를 재정의합니다.

부모 창 클래스에서 특정 WM_NOTIFY 메시지 또는 WM_NOTIFY 메시지 범위에 대한 처리기를 제공하는 경우 해당 메시지를 보내는 자식 컨트롤에 반영된 메시지 처리기가 없는 경우에만 처리기가 ON_NOTIFY_REFLECT()호출됩니다. 메시지 맵에서 사용하는 ON_NOTIFY_REFLECT_EX() 경우 메시지 처리기가 부모 창에서 메시지를 처리하도록 허용할 수도 있고 허용하지 않을 수도 있습니다. 처리기가 FALSE를 반환하는 경우 메시지는 부모도 처리하지만 TRUE를 반환하는 호출은 부모가 처리할 수 없습니다. 반영된 메시지는 알림 메시지 전에 처리됩니다.

WM_NOTIFY 메시지를 보내면 컨트롤에서 메시지를 처리할 수 있는 첫 번째 기회가 제공됩니다. 다른 반영된 메시지가 전송되면 부모 창에서 해당 메시지를 처리할 수 있는 첫 번째 기회가 있으며 컨트롤은 반영된 메시지를 받습니다. 이렇게 하려면 처리기 함수와 컨트롤의 클래스 메시지 맵에 적절한 항목이 필요합니다.

반영된 메시지에 대한 메시지 맵 매크로는 일반 알림과 약간 다릅니다. 일반적인 이름에 _REFLECT 추가되었습니다. 예를 들어 부모에서 WM_NOTIFY 메시지를 처리하려면 부모 메시지 맵에서 매크로 ON_NOTIFY 사용합니다. 자식 컨트롤에서 반영된 메시지를 처리하려면 자식 컨트롤의 메시지 맵에서 ON_NOTIFY_REFLECT 매크로를 사용합니다. 경우에 따라 매개 변수도 다릅니다. ClassWizard는 일반적으로 메시지 맵 항목을 추가하고 올바른 매개 변수를 사용하여 기본 함수 구현을 제공할 수 있습니다.

새 WM_NOTIFY 메시지에 대한 자세한 내용은 TN061: ON_NOTIFY 및 WM_NOTIFY 메시지를 참조하세요.

반영된 메시지에 대한 메시지 맵 항목 및 처리기 함수 프로토타입

반영된 컨트롤 알림 메시지를 처리하려면 아래 표에 나열된 메시지 맵 매크로 및 함수 프로토타입을 사용합니다.

ClassWizard는 일반적으로 이러한 메시지 맵 항목을 추가하고 기본 함수 구현을 제공할 수 있습니다. 반영된 메시지에 대한 처리기를 정의하는 방법에 대한 자세한 내용은 반영된 메시지에 대한 메시지 처리기 정의를 참조하세요.

메시지 이름에서 반사된 매크로 이름으로 변환하려면 앞에 ON_ 추가하고 _REFLECT 추가합니다. 예를 들어 WM_CTLCOLOR ON_WM_CTLCOLOR_REFLECT 됩니다. (반영할 수 있는 메시지를 보려면 아래 표의 매크로 항목에서 반대 변환을 수행합니다.)

위의 규칙에 대한 세 가지 예외는 다음과 같습니다.

  • WM_COMMAND 알림에 대한 매크로가 ON_CONTROL_REFLECT.

  • WM_NOTIFY 리플렉션에 대한 매크로는 ON_NOTIFY_REFLECT.

  • ON_UPDATE_COMMAND_UI 리플렉션에 대한 매크로는 ON_UPDATE_COMMAND_UI_REFLECT.

위의 각 특수 사례에서 처리기 멤버 함수의 이름을 지정해야 합니다. 다른 경우에는 처리기 함수에 표준 이름을 사용해야 합니다.

매개 변수의 의미와 함수의 반환 값은 함수 이름 또는 On 앞에 추가된 함수 이름 아래에 설명되어 있습니다. 예를 들어 . CtlColorOnCtlColor 여러 개의 반영된 메시지 처리기는 부모 창의 유사한 처리기보다 더 적은 매개 변수가 필요합니다. 아래 표의 이름과 설명서의 정식 매개 변수 이름과 일치하기만 하면됩니다.

맵 항목 함수 프로토타입
ON_CONTROL_REFLECT(wNotifyCode,)memberFxn afx_msg voidmemberFxn( );
ON_NOTIFY_REFLECT(wNotifyCode,)memberFxn afx_msg voidmemberFxn( NMHDR*pNotifyStruct, LRESULT*결과);
ON_UPDATE_COMMAND_UI_REFLECT(memberFxn) afx_msg voidmemberFxn( CCmdUI);*pCmdUI
ON_WM_CTLCOLOR_REFLECT( ) afx_msg HBRUSH CtlColor (CDCpDC*, UINT);nCtlColor
ON_WM_DRAWITEM_REFLECT( ) afx_msg void DrawItem(LPDRAWITEMSTRUCTlpDrawItemStruct);
ON_WM_MEASUREITEM_REFLECT( ) afx_msg void MeasureItem(LPMEASUREITEMSTRUCTlpMeasureItemStruct);
ON_WM_DELETEITEM_REFLECT( ) afx_msg void DeleteItem(LPDELETEITEMSTRUCTlpDeleteItemStruct);
ON_WM_COMPAREITEM_REFLECT( ) afx_msg int CompareItem(LPCOMPAREITEMSTRUCTlpCompareItemStruct);
ON_WM_CHARTOITEM_REFLECT( ) afx_msg int CharToItem (UINTnKey, UINT);nIndex
ON_WM_VKEYTOITEM_REFLECT( ) afx_msg int VKeyToItem (UINTnKey, UINT);nIndex
ON_WM_HSCROLL_REFLECT( ) afx_msg void HScroll (UINTnSBCode, UINT);nPos
ON_WM_VSCROLL_REFLECT( ) afx_msg void VScroll (UINTnSBCode, UINT);nPos
ON_WM_PARENTNOTIFY_REFLECT( ) afx_msg void ParentNotify(UINTmessage, LPARAM);lParam

ON_NOTIFY_REFLECT 및 ON_CONTROL_REFLECT 매크로에는 두 개 이상의 개체(예: 컨트롤 및 부모)가 지정된 메시지를 처리할 수 있는 변형이 있습니다.

맵 항목 함수 프로토타입
ON_NOTIFY_REFLECT_EX(wNotifyCode,)memberFxn afx_msg BOOLmemberFxn( NMHDR*pNotifyStruct, LRESULT*결과);
ON_CONTROL_REFLECT_EX(wNotifyCode,)memberFxn afx_msg BOOLmemberFxn( );

반영된 메시지 처리: 재사용 가능한 컨트롤의 예

이 간단한 예제에서는 다시 사용할 수 있는 컨트롤을 CYellowEdit만듭니다. 컨트롤은 노란색 배경에 검은색 텍스트를 표시한다는 점을 제외하고 일반 편집 컨트롤과 동일하게 작동합니다. 컨트롤이 다른 색을 표시할 수 있도록 하는 멤버 함수를 CYellowEdit 쉽게 추가할 수 있습니다.

재사용 가능한 컨트롤을 만드는 예제를 시도하려면

  1. 기존 애플리케이션에서 새 대화 상자를 만듭니다. 자세한 내용은 대화 편집항목을 참조하세요.

    재사용 가능한 컨트롤을 개발할 애플리케이션이 있어야 합니다. 사용할 기존 애플리케이션이 없는 경우 AppWizard를 사용하여 대화 상자 기반 애플리케이션을 만듭니다.

  2. 프로젝트가 Visual C++에 로드된 상태에서 ClassWizard를 사용하여 기반으로 호출 CYellowEdit 되는 새 클래스를 만듭니다 CEdit.

  3. 클래스에 세 개의 멤버 변수를 추가합니다 CYellowEdit . 처음 두 가지 는 텍스트 색과 배경색을 보유하는 COLORREF 변수입니다. 세 번째는 배경을 그리기 CBrush 위해 브러시를 보유하는 개체입니다. 개체 CBrush 를 사용하면 브러시를 한 번 만들고, 그 후에만 참조하고, 컨트롤이 제거되면 브러시를 CYellowEdit 자동으로 삭제할 수 있습니다.

  4. 다음과 같이 생성자를 작성하여 멤버 변수를 초기화합니다.

    CYellowEdit::CYellowEdit()
    {
        m_clrText = RGB(0, 0, 0);
        m_clrBkgnd = RGB(255, 255, 0);
        m_brBkgnd.CreateSolidBrush(m_clrBkgnd);
    }
    
  5. ClassWizard를 사용하여 반영된 WM_CTLCOLOR 메시지에 대한 처리기를 클래스에 추가합니다 CYellowEdit . 처리할 수 있는 메시지 목록의 메시지 이름 앞에 있는 등호는 메시지가 반영됨을 나타냅니다. 이는 반영된 메시지에 대한 메시지 처리기 정의에 설명 되어 있습니다.

    ClassWizard는 다음과 같은 메시지 맵 매크로 및 기본 함수를 추가합니다.

    ON_WM_CTLCOLOR_REFLECT()
    // Note: other code will be in between....
    
    HBRUSH CYellowEdit::CtlColor(CDC* pDC, UINT nCtlColor)
    {
        // TODO: Change any attributes of the DC here
        // TODO: Return a non-NULL brush if the
        //       parent's handler should not be called
        return NULL;
    }
    
  6. 함수 본문을 다음 코드로 바꿉니다. 이 코드는 컨트롤의 나머지 부분에 대한 텍스트 색, 텍스트 배경색 및 배경색을 지정합니다.

    pDC->SetTextColor(m_clrText);   // text
    pDC->SetBkColor(m_clrBkgnd);    // text bkgnd
    return m_brBkgnd;               // ctl bkgnd
    
  7. 대화 상자에서 편집 컨트롤을 만든 다음 컨트롤 키를 누른 상태에서 편집 컨트롤을 두 번 클릭하여 멤버 변수에 연결합니다. 멤버 변수 추가 대화 상자에서 변수 이름을 완료하고 범주에 대해 "Control"을 선택한 다음 변수 형식에 대해 "CYellowEdit"를 선택합니다. 대화 상자에서 탭 순서를 설정하는 것을 잊지 마세요. 또한 대화 상자의 헤더 파일에 컨트롤의 CYellowEdit 헤더 파일을 포함해야 합니다.

  8. 애플리케이션을 빌드하고 실행합니다. 편집 컨트롤에는 노란색 배경이 있습니다.

참고 항목

번호별 기술 참고 사항
범주별 기술 참고 사항