Я не эксперт по MFC, но за последние 15 с лишним лет я сделал около дюжины настраиваемых элементов управления. Я только что сделал CButton
с нестандартной графикой.
Вот проблема: конечно, мне нужно установить BS_OWNERDRAW
. У меня есть OnNcCreate()
метод, который я вырезал и вставлял более 15 лет, который всегда работал в моих пользовательских элементах управления, но по какой-то причине он сейчас не вызывается.
У меня нет интереса или даже понимания OnNcCreate()
, за исключением того факта, что это было место, где я получил BS_OWNERDRAW
набор в первый раз, когда я попытался написать настраиваемый элемент управления.
Вопрос: что мешает OnNcCreate()
звонить? Или есть другое место, где я мог бы или должен был установить BS_OWNERDRAW
?
Рабочий класс определяется с помощью:
class CGood : public CStatic {
Нерабочий определяется с помощью:
class CBad : public CButton {
Оба они прототипируют метод следующим образом:
afx_msg int OnNcCreate( LPCREATESTRUCT lpCreateStruct );
Метод написан идентично (кроме имени класса):
int CGood::OnNcCreate( LPCREATESTRUCT pcrs ) {
wStyleBits = LOWORD( pcrs->style );
DWORD dwStyleSuperclass = MAKELONG( ES_LEFT, HIWORD( pcrs->style ) );
dwStyleSuperclass |= BS_OWNERDRAW;
::SetWindowLong( m_hWnd, GWL_STYLE, dwStyleSuperclass );
pcrs->style = dwStyleSuperclass;
return CStatic::OnNcCreate( pcrs );
}
В диалоговом окне используются как хорошие, так и плохие классы, использующие редактор диалоговых окон Visual Studio 2017, например CustomControl. И хороший, и плохой классы имеют расширенный стиль 0x0 и стиль 0x50010000. Оба: Отключено = Ложь, Идентификатор справки = Ложь, Видимый = Истина, Класс = Хороший или Плохой по мере необходимости.
При запуске приложение вызывает RegisterControlClass()
метод каждого класса:
static WNDPROC pfnWndProc = NULL;
BOOL CBad::RegisterControlClass() {
WNDCLASS wcls;
static const TCHAR szClass[] = _T( "CBad" );
if ( ::GetClassInfo( AfxGetInstanceHandle(), szClass, &wcls ) )
return wcls.lpfnWndProc == ( WNDPROC ) CBad::WndProcHook;
VERIFY( ::GetClassInfo( NULL, _T( "button" ), &wcls ) );
pfnWndProc = wcls.lpfnWndProc;
wcls.lpfnWndProc = CBad::WndProcHook;
wcls.hInstance = AfxGetInstanceHandle();
wcls.lpszClassName = szClass;
return RegisterClass( &wcls ) != 0;
}
LRESULT CALLBACK EXPORT CBad::WndProcHook( HWND hWnd, UINT msg,
WPARAM wParam, LPARAM lParam ) {
CBad* pthis = new CBad();
pthis->Attach( hWnd );
pthis->m_pfnSuper = pfnWndProc;
::SetWindowLong( hWnd, GWL_WNDPROC, ( DWORD )AfxWndProc );
#ifdef STRICT
return ::CallWindowProc( AfxWndProc, hWnd, msg, wParam, lParam );
#else
return ::CallWindowProc( ( FARPROC )AfxWndProc, hWnd, msg, wParam, lParam );
#endif
}
(Забавно: я заметил, что в CGood
, производном от CStatic
, там по ошибке есть «кнопка», и он работает нормально; он перестает работать, если я перехожу на «статический». Я рассмотрю это позже. У плохого класса есть «кнопка» и действительно является CButton
подклассом.)
Что я сделал для подтверждения проблемы: когда я удаляю BS_OWNERDRAW
из CGood::OnNcCreate()
, он перестает вызывать DrawItem()
. Так что я уверен, что здесь устанавливается этот флаг.
Установка точки останова в CGood::OnNcCreate()
и CBad::OnNcCreate(),
CBad просто не вызывается.
Я нашел в Интернете примеры установки BS_OWNERDRAW
в PreSubclassWindow()
, OnCreate()
и CreateEx()
, ни один из которых не работает, в некоторых случаях по причинам, которые я думаю, я понимаю. (Например, вы не можете просто установить флаги в OnCreate () и вызвать метод суперкласса, потому что он, в конечном итоге, получает флаги не из заданного вами параметра, а из другого источника.)
Я пробовал изменить суперкласс CBad на CStatic, но OnNcCreate () по-прежнему не вызывается.
Я пробовал установить BS_OWNERDRAW
в диалоговом окне OnInitDialog()
, и это действительно правильно отображает подкласс кнопки CBad. Итак, я знаю, что не случайно создаю их с каким-то другим подклассом и т. Д.
CBad* pcbut = (CBad*) GetDlgItem( IDC_MARKCHECK );
pcbut->ModifyStyle(0, BS_OWNERDRAW);