TN014: 사용자 지정 컨트롤

이 노트는 사용자 지정과 자체 그리기 컨트롤에 대한 MFC 지원을 설명합니다. 또한 동적 서브클래싱을 설명하고 CWnd 개체와 HWNDs 간의 관계를 설명합니다.

MFC 샘플 애플리케이션 CTRLTEST는 여러 사용자 지정 컨트롤을 사용하는 방법을 보여줍니다. MFC 일반 샘플 CTRLTEST 및 온라인 도움말에 대한 소스 코드를 참조하세요.

소유자 그리기 컨트롤/메뉴

Windows는 Windows 메시지를 사용하여 소유자 그리기 컨트롤 및 메뉴에 대한 지원을 제공합니다. 모든 컨트롤 또는 메뉴의 부모 창은 이러한 메시지를 수신하고 그에 대한 응답으로 함수를 호출합니다. 이러한 함수를 재정의하여 소유자 그리기 컨트롤 또는 메뉴의 시각적 모양과 동작을 사용자 지정할 수 있습니다.

MFC는 다음과 같은 함수로 소유자 그리기를 직접 지원합니다.

CWnd 파생 클래스에서 이러한 함수를 재정의하여 사용자 지정 그리기 동작을 구현할 수 있습니다.

이 방법은 재사용 가능한 코드를 일으키지 않습니다. 두 개의 다른 CWnd 클래스에 두 개의 비슷한 컨트롤이 있으면 두 위치에서 사용자 지정 컨트롤 동작을 구현해야 합니다. MFC로 지원되는 자체 그리기 컨트롤 아키텍처는 이 문제를 해결합니다.

자체 그리기 컨트롤 및 메뉴

MFC는 표준 소유자 그리기 메시지에 대한 기본 구현( CWndCMenu 클래스)을 제공합니다. 이러한 기본 구현은 소유자 그리기 매개 변수를 디코딩하고 소유자 그리기 메시지를 컨트롤 또는 메뉴에 위임합니다. 자체 그리기라고 부르는 이유는 그리기 코드가 소유자 창이 아닌 컨트롤 또는 메뉴의 클래스에 있기 때문입니다.

자체 그리기 컨트롤을 사용하면 소유자 그리기 의미 체계를 사용해서 컨트롤을 표시하는 재사용 가능한 컨트롤 클래스를 빌드할 수 있습니다. 컨트롤 그리기에 대한 코드는 해당 부모가 아닌 컨트롤 클래스에 있습니다. 이러한 방식은 사용자 지정 컨트롤 프로그래밍에 대한 개체 지향 접근 방식입니다. 다음 함수 목록을 자체 그리기 클래스에 추가합니다.

  • 자체 그리기 단추:

    CButton:DrawItem(LPDRAWITEMSTRUCT);
    // insert code to draw this button
    
  • 자체 그리기 메뉴:

    CMenu:MeasureItem(LPMEASUREITEMSTRUCT);
    // insert code to measure the size of an item in this menu
    CMenu:DrawItem(LPDRAWITEMSTRUCT);
    // insert code to draw an item in this menu
    
  • 자체 그리기 목록 상자:

    CListBox:MeasureItem(LPMEASUREITEMSTRUCT);
    // insert code to measure the size of an item in this list box
    CListBox:DrawItem(LPDRAWITEMSTRUCT);
    // insert code to draw an item in this list box
    
    CListBox:CompareItem(LPCOMPAREITEMSTRUCT);
    // insert code to compare two items in this list box if LBS_SORT
    CListBox:DeleteItem(LPDELETEITEMSTRUCT);
    // insert code to delete an item from this list box
    
  • 자체 그리기 콤보 상자:

    CComboBox:MeasureItem(LPMEASUREITEMSTRUCT);
    // insert code to measure the size of an item in this combo box
    CComboBox:DrawItem(LPDRAWITEMSTRUCT);
    // insert code to draw an item in this combo box
    
    CComboBox:CompareItem(LPCOMPAREITEMSTRUCT);
    // insert code to compare two items in this combo box if CBS_SORT
    CComboBox:DeleteItem(LPDELETEITEMSTRUCT);
    // insert code to delete an item from this combo box
    

소유자 그리기 구조체(DRAWITEMSTRUCT, MEASUREITEMSTRUCT, COMPAREITEMSTRUCT 및 DELETEITEMSTRUCT)에 대한 자세한 내용은 각각에 CWnd::OnCompareItemCWnd::OnDeleteItemCWnd::OnMeasureItem대한 CWnd::OnDrawItemMFC 설명서를 참조하세요.

자체 그리기 컨트롤 및 메뉴 사용

자체 그리기 메뉴에 대해서는 OnMeasureItemOnDrawItem 메서드를 모두 재정의해야 합니다.

자체 그리기 목록 상자 및 콤보 상자에 대해서는 OnMeasureItemOnDrawItem을 재정의해야 합니다. 대화 상자 서식 파일에서 목록 상자의 LBS_OWNERDRAWVARIABLE 스타일이나 콤보 상자의 CBS_OWNERDRAWVARIABLE 스타일을 지정해야 합니다. 자체 그리기 컨트롤이 목록 상자에 연결되기 전에 고정 항목 높이가 결정되므로 OWNERDRAWFIXED 스타일은 자체 그리기 항목에서 작동하지 않습니다. (메서드를 사용할 수 있습니다. CListBox::SetItemHeightCComboBox::SetItemHeight 를 사용하여 이 제한을 극복합니다.)

OWNERDRAWVARIABLE 스타일로 전환하면 시스템에서 NOINTEGRALHEIGHT 스타일을 컨트롤에 강제로 적용합니다. 컨트롤은 가변 크기 항목으로 정수 계열 높이를 계산할 수 없으므로 INTEGRALHEIGHT의 기본 스타일은 무시되고 컨트롤은 항상 NOINTEGRALHEIGHT입니다. 항목이 고정된 높이인 경우 컨트롤 크기를 항목 크기의 정수 배율로 지정하여 항목이 일부만 그려지지 않도록 방지할 수 있습니다.

LBS_SORT 또는 CBS_SORT 스타일이 있는 자체 그리기 목록 상자 및 콤보 상자의 경우 메서드를 재정의 OnCompareItem 해야 합니다.

자체 그리기 목록 상자 및 콤보 상자의 경우 OnDeleteItem은 일반적으로 재정의되지 않습니다. 특수 처리를 수행하려는 경우에는 OnDeleteItem을 재정의할 수 있습니다. 이러한 경우를 적용할 수 있는 한 가지 사례는 추가 메모리 또는 기타 리소스가 각 목록 상자 또는 콤보 상자 항목에 저장되어 있는 경우입니다.

자체 그리기 컨트롤 및 메뉴의 예제

MFC 일반 샘플 CTRLTEST 는 자체 그리기 메뉴 및 자체 그리기 목록 상자의 샘플을 제공합니다.

자체 그리기 단추의 가장 일반적인 예는 비트맵 단추입니다. 비트맵 단추는 서로 다른 상태의 비트맵 이미지를 1~3개 보여주는 단추입니다. 이 예제는 MFC 클래스 CBitmapButton에 제공됩니다.

동적 서브클래싱

일부 경우에는 이미 존재하는 개체의 기능을 변경해야 할 수 있습니다. 이전 예제에서는 컨트롤이 생성되기 전에 사용자가 컨트롤을 사용자 지정해야 했습니다. 동적 서브클래싱은 사용자가 이미 생성된 컨트롤을 사용자 지정할 수 있게 해줍니다.

서브클래싱은 창을 사용자 지정 WndProc 으로 대체 WndProc 하고 기본 기능을 위해 이전 WndProc 버전을 호출하는 Windows 용어입니다.

이 용어를 C++ 클래스 파생과 혼동해서는 안됩니다. 설명을 위해 C++ 용어 기본 클래스 및 파생 클래스는 Windows 개체 모델의 슈퍼 클래스 및 서브클래스와 유사합니다. MFC의 C++ 파생과 Windows의 서브클래싱은 기능적으로 비슷하지만 C++의 경우 동적 서브클래싱이 지원되지 않습니다.

CWnd 클래스는 C++ 개체(CWnd에서 파생)와 Windows의 창 개체(HWND) 사이의 연결을 제공합니다.

이러한 연결에는 세 가지 일반적인 특성이 존재합니다.

  • CWndHWND를 만듭니다. CWnd에서 파생된 클래스를 만들어서 파생 클래스의 동작을 수정할 수 있습니다. 애플리케이션에서 HWND CWnd::Create를 호출 할 때 생성됩니다.

  • 이 애플리케이션은 CWnd를 기존 HWND에 연결합니다. 기존 창의 동작은 수정되지 않습니다. 위임의 경우이며 CWnd::Attach를 호출하여 개체에 대한 기존 HWND 별칭을 호출할 수 CWnd 있습니다.

  • CWnd가 기존 HWND에 연결되고 파생 클래스의 동작을 수정할 수 있습니다. 런타임에 Windows 개체의 동작을 바꾸고, 따라서 클래스도 바꾸기 때문에 이를 동적 서브클래싱이라고 부릅니다.

CWnd::SubclassWindowCWnd::SubclassDlgItem 메서드를 사용하여 동적 서브클래싱을 수행할 수 있습니다.

두 루틴은 모두 CWnd 개체를 기존 HWND에 연결합니다. SubclassWindowHWND를 직접 사용합니다. SubclassDlgItem은 컨트롤 ID 및 부모 창을 사용하는 도우미 함수입니다. SubclassDlgItem은 대화 상자 템플릿에서 생성된 대화 상자 컨트롤에 C++ 개체를 연결하기 위해 설계되었습니다.

SubclassWindowSubclassDlgItem를 사용하는 경우의 몇 가지 예는 CTRLTEST 예제를 참조하세요.

참고 항목

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