Элементы управления подклассами
Если элемент управления выполняет почти все необходимое, но вам потребуется несколько дополнительных функций, вы можете изменить или добавить функции в исходный элемент управления, подклассив его. Подкласс может иметь все функции существующего класса, а также любые дополнительные функции, которые вы хотите предоставить.
В этом документе описывается, как создаются подклассы и содержатся следующие разделы.
- Элементы управления подклассами до ComCtl32.dll версии 6
- Элементы управления подклассами с помощью ComCtl32.dll версии 6
Элементы управления подклассами до ComCtl32.dll версии 6
Элемент управления можно поместить в подкласс и сохранить пользовательские данные в элементе управления. Это происходит при использовании версий ComCtl32.dll до версии 6. Существует ряд недостатков при создании подклассов с более ранними версиями ComCtl32.dll.
Чтобы сделать новый элемент управления, лучше всего начать с одного из распространенных элементов управления Windows и расширить его в соответствии с определенной потребностью. Чтобы расширить элемент управления, создайте элемент управления и замените ее существующую процедуру окна новым. Новая процедура перехватывает сообщения элемента управления и либо действует над ними, либо передает их исходной процедуре для обработки по умолчанию. Используйте функцию SetWindowLong или SetWindowLongPtr, чтобы заменить WNDPROC элемента управления. В следующем примере кода показано, как заменить WNDPROC.
OldWndProc = (WNDPROC)SetWindowLongPtr (hButton,
GWLP_WNDPROC, (LONG_PTR)NewWndProc);
Хранение пользовательских данных
Может потребоваться хранить пользовательские данные с отдельным окном. Эти данные можно использовать новой процедурой окна для определения способа рисования элемента управления или места отправки определенных сообщений. Например, можно использовать данные для хранения указателя класса C++ на класс, представляющий элемент управления. В следующем примере кода показано, как использовать SetProp для хранения данных с окном.
SetProp (hwnd, TEXT("MyData"), (HANDLE)pMyData);
Недостатки старого подклассного подхода
В следующем списке перечислены некоторые недостатки использования ранее описанного подхода к подклассу элемента управления.
- Процедуру окна можно заменить только один раз.
- После его создания сложно удалить подкласс.
- Связывание частных данных с окном неэффективно.
- Чтобы вызвать следующую процедуру в цепочке подклассов, вы не можете привести старую процедуру окна и вызвать ее, необходимо вызвать ее с помощью функции CallWindowProc.
Элементы управления подклассами с помощью ComCtl32.dll версии 6
Примечание.
ComCtl32.dll версии 6 только Юникод. Общие элементы управления, поддерживаемые ComCtl32.dll версии 6, не должны быть подклассами (или суперклассами) с процедурами окна ANSI.
ComCtl32.dll версии 6 содержит четыре функции, которые упрощают создание подклассов и устраняют недостатки, которые ранее обсуждались. Новые функции инкапсулируют управление, связанное с несколькими наборами эталонных данных, поэтому разработчик может сосредоточиться на функциях программирования, а не на управлении подклассами. Ниже перечислены функции подкласса:
SetWindowSubclass
Эта функция используется для первоначального подкласса окна. Каждый подкласс однозначно определяется адресом pfnSubclass и его uIdSubclass. Оба из них являются параметрами функции SetWindowSubclass . Несколько подклассов могут совместно использовать одну и ту же процедуру подкласса, и идентификатор может идентифицировать каждый вызов. Чтобы изменить эталонные данные, можно выполнить последующие вызовы SetWindowSubclass. Важное преимущество заключается в том, что каждый экземпляр подкласса имеет собственные эталонные данные.
Объявление процедуры подкласса немного отличается от обычной процедуры окна, так как она содержит два дополнительных фрагмента данных: идентификатор подкласса и эталонные данные. Показано это в последних двух параметрах следующего объявления функции.
LRESULT CALLBACK MyWndProc (HWND hWnd, UINT msg,
WPARAM wParam, LPARAM lParam, UINT_PTR uIdSubclass,
DWORD_PTR dwRefData);
Каждый раз при получении сообщения новой процедурой окна идентификатор подкласса и справочные данные включаются.
Примечание.
Все строки, передаваемые процедуре, являются строками Юникода, даже если Юникод не указан в качестве определения препроцессора.
В следующем примере показана скелетная реализация процедуры окна для подклассированного элемента управления.
LRESULT CALLBACK OwnerDrawButtonProc(HWND hWnd, UINT uMsg, WPARAM wParam,
LPARAM lParam, UINT_PTR uIdSubclass, DWORD_PTR dwRefData)
{
switch (uMsg)
{
case WM_PAINT:
.
.
.
return TRUE;
// Other cases...
}
return DefSubclassProc(hWnd, uMsg, wParam, lParam);
}
Процедура окна может быть присоединена к элементу управления в обработчике WM_INITDIALOG процедуры диалога, как показано в следующем примере.
case WM_INITDIALOG:
{
HWND button = GetDlgItem(hDlg, IDC_OWNERDRAWBUTTON);
SetWindowSubclass(button, OwnerDrawButtonProc, 0, 0);
return TRUE;
}
GetWindowSubclass
Эта функция извлекает сведения о подклассе. Например, можно использовать GetWindowSubclass для доступа к эталонным данным.
RemoveWindowSubclass
Эта функция удаляет подклассы. RemoveWindowSubclass в сочетании с SetWindowSubclass позволяет динамически добавлять и удалять подклассы.
DefSubclassProc
Функция DefSubclassProc вызывает следующий обработчик в цепочке подклассов. Функция также извлекает правильный идентификатор и справочные данные и передает сведения в следующую процедуру окна.