TN014. Пользовательские элементы управления

В этой заметке описывается поддержка MFC для пользовательских и саморисовки элементов управления. Он также описывает динамическое подклассирование и описывает связь между объектами CWnd и HWNDs.

Пример приложения MFC CTRLTEST показывает, как использовать множество пользовательских элементов управления. См. исходный код для примера CTRLTEST и справки по сети MFC.

Элементы управления и меню владельца

Windows обеспечивает поддержку элементов управления и меню владельца с помощью сообщений Windows. Родительское окно любого элемента управления или меню получает эти сообщения и вызывает функции в ответ. Эти функции можно переопределить, чтобы настроить внешний вид и поведение элемента управления или меню владельца.

MFC напрямую поддерживает рисование владельца со следующими функциями:

Эти функции можно переопределить в CWnd производном классе для реализации пользовательского поведения рисования.

Этот подход не приводит к повторному использовании кода. Если у вас есть два аналогичных элемента управления в двух разных CWnd классах, необходимо реализовать поведение пользовательского элемента управления в двух расположениях. Архитектура саморисовки, поддерживаемая MFC, решает эту проблему.

Самостоятельное рисование элементов управления и меню

MFC предоставляет реализацию по умолчанию (в CWndклассах CMenu ) для стандартных сообщений нарисовки владельцев. Эта реализация по умолчанию декодирует параметры рисования владельца и делегирует сообщения, нарисованные владельцем, элементам управления или меню. Это называется самостоятельным рисованием, так как код рисования находится в классе элемента управления или меню, а не в окне владельца.

С помощью элементов управления самообслуживания можно создавать повторно используемые классы элементов управления, использующие семантику рисования владельца для отображения элемента управления. Код для рисования элемента управления находится в классе элемента управления, а не в родительском. Это объектно-ориентированный подход к программированию пользовательского элемента управления. Добавьте следующий список функций в собственные классы рисования:

  • Для кнопок самостоятельного рисования:

    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) см. в документации по MFC для CWnd::OnDrawItem, CWnd::OnMeasureItemCWnd::OnCompareItemи CWnd::OnDeleteItem соответственно.

Использование элементов управления и меню самостоятельного рисования

Для самостоятельного рисования меню необходимо переопределить как методы, так OnMeasureItem и OnDrawItem методы.

Для саморисовки списков и полей со списком OnMeasureItem необходимо переопределить и OnDrawItem. Необходимо указать стиль LBS_OWNERDRAWVARIABLE для полей списка или CBS_OWNERDRAWVARIABLE стиля для полей со списком в шаблоне диалога. Стиль OWNERDRAWFIXED не будет работать с элементами самостоятельного рисования, так как фиксированная высота элемента определяется перед присоединением элементов управления самостоятельной рисования к списку. (Методы можно использоватьCListBox::SetItemHeight и CComboBox::SetItemHeight, чтобы преодолеть это ограничение.)

Переключение на стиль OWNERDRAWVARIABLE приведет к применению к элементу управления стиля NOINTEGRALHEIGHT. Так как элемент управления не может вычислить целочисленную высоту с элементами переменной размера, стиль ПО умолчанию ЦЕЛОЧИСЛЕННОГО ЭЛЕМЕНТА не учитывается, и элемент управления всегда NOINTEGRALHEIGHT. Если элементы имеют фиксированную высоту, можно предотвратить рисование частичных элементов, указав размер элемента управления для целочисленного умножения размера элемента.

Для самостоятельного рисования списков и полей со списком с помощью стиля LBS_SORT или CBS_SORT необходимо переопределить OnCompareItem метод.

Для саморисовки списков OnDeleteItem и полей со списком обычно не переопределяется. Можно переопределить OnDeleteItem , если вы хотите выполнить любую специальную обработку. Один из случаев, когда это может быть применимо, заключается в том, что при хранении дополнительной памяти или других ресурсов с каждым полем списка или элементом поля со списком.

Примеры элементов управления и меню самостоятельного рисования

В примере CTRLTEST для MFC приведены примеры меню самостоятельного рисования и поле списка самостоятельного рисования.

Наиболее типичным примером самостоятельной кнопки рисования является кнопка растрового рисунка. Кнопка растрового изображения — это кнопка, показывающая один, два или три растровых изображения для разных состояний. Пример этого представлен в классе MFC CBitmapButton.

Динамическое подклассирование

Иногда требуется изменить функциональные возможности уже существующего объекта. Предыдущие примеры требуют настройки элементов управления до их создания. Динамическое подклассирование позволяет настроить элемент управления, который уже создан.

Подкласс — это термин Windows для замены WndProc окна настроенным WndProc и вызовом старой WndProc функции по умолчанию.

Это не следует путать с производным классом C++. Для уточнения базовый класс И производный класс C++ аналогичен суперклассу и подклассу в объектной модели Windows. Производные C++ с подклассами MFC и Windows функционально похожи, за исключением того, что C++ не поддерживает динамическое подклассирование.

Класс CWnd обеспечивает соединение между объектом C++ (производным отCWnd) и объектом окна Windows (известным как ).HWND

Существует три распространенных способа:

  • CWndHWNDсоздает объект . Поведение в производном классе можно изменить, создав класс, производный от CWnd. Создается HWND при вызове приложения CWnd::Create.

  • Приложение присоединяет приложение CWnd к существующему HWND. Поведение существующего окна не изменяется. Это случай делегирования и это возможно путем вызова CWnd::Attach к псевдониму существующего HWNDCWnd объекта.

  • CWnd присоединен к существующему HWND и можно изменить поведение в производном классе. Это называется динамическим подклассом, так как мы изменяем поведение и, следовательно, класс объекта Windows во время выполнения.

Динамическое подклассирование можно достичь с помощью методов CWnd::SubclassWindow иCWnd::SubclassDlgItem.

Обе подпрограммы присоединяют CWnd объект к существующему HWNDобъекту. SubclassWindow принимает напрямую HWND . SubclassDlgItem является вспомогательной функцией, которая принимает идентификатор элемента управления и родительское окно. SubclassDlgItem предназначен для присоединения объектов C++ к элементам управления диалогом, созданным на основе шаблона диалогового окна.

Пример CTRLTEST см. в нескольких примерах использования SubclassWindow и SubclassDlgItem.

См. также

Технические примечания по номеру
Технические примечания по категории