Я создал два экземпляра класса Fred Acker's CHoverButtonEx с небольшим изменением, включив отключенное состояние.
Эти кнопки существуют в немодальном диалоговом окне, которое содержит следующие свойства:
IDD_MY_DIALOG DIALOGEX 0, 0, 162, 27
STYLE DS_SETFONT | WS_POPUP
EXSTYLE WS_EX_TOPMOST | WS_EX_TOOLWINDOW
FONT 9, "Arial", 400, 0, 0x0
BEGIN
CONTROL 146,IDC_STATIC_BKGND,"Static",SS_BITMAP,0,0,162,27
LTEXT "",IDC_STATIC_1,6,4,101,9,SS_WORDELLIPSIS
LTEXT "",IDC_STATIC_2,6,15,101,9
CONTROL "",IDC_BUTTON_1,"Button",BS_OWNERDRAW | WS_TABSTOP,108,4,24,19
CONTROL "",IDC_BUTTON_2,"Button",BS_OWNERDRAW | WS_TABSTOP,134,4,24,19
END
Все работает хорошо с кнопками, за исключением того, что теперь мне нужно реализовать состояние фокуса, но поведение странное и неожиданное.
В моем обработчике сообщений DrawItem у меня есть следующий код, которыйфункционирует почти так же, как и оригинал, за исключением некоторых вещей, которые я убрал, которые не были нужны:
void CHoverButtonEx::DrawItem(LPDRAWITEMSTRUCT lpDrawItemStruct)
{
// Do other stuff above and now find the state and draw the bitmap
if(lpDrawItemStruct->itemState & ODS_SELECTED)
{
//mydc->BitBlt(0,0,m_ButtonSize.cx,m_ButtonSize.cy,pMemDC,m_ButtonSize.cx,0,SRCCOPY);
mydc->StretchBlt(0,0, lpDrawItemStruct->rcItem.right-lpDrawItemStruct->rcItem.left,
lpDrawItemStruct->rcItem.bottom-lpDrawItemStruct->rcItem.top,
pMemDC,m_ButtonSize.cx,0, m_ButtonSize.cx,m_ButtonSize.cy, SRCCOPY );
}
else
{
if(m_bHover)
{
//mydc->BitBlt(0,0,m_ButtonSize.cx,m_ButtonSize.cy,pMemDC,m_ButtonSize.cx*2,0,SRCCOPY);
mydc->StretchBlt(0,0, lpDrawItemStruct->rcItem.right-lpDrawItemStruct->rcItem.left,
lpDrawItemStruct->rcItem.bottom-lpDrawItemStruct->rcItem.top,
pMemDC,m_ButtonSize.cx*2,0, m_ButtonSize.cx,m_ButtonSize.cy, SRCCOPY );
}
else
{
if (IsWindowEnabled())
{
//mydc->BitBlt(0,0,m_ButtonSize.cx,m_ButtonSize.cy,pMemDC,0,0,SRCCOPY);
mydc->StretchBlt(0,0, lpDrawItemStruct->rcItem.right-lpDrawItemStruct->rcItem.left,
lpDrawItemStruct->rcItem.bottom-lpDrawItemStruct->rcItem.top,
pMemDC,0,0, m_ButtonSize.cx,m_ButtonSize.cy, SRCCOPY );
}
else
{
//mydc->BitBlt(0,0,m_ButtonSize.cx,m_ButtonSize.cy,pMemDC,m_ButtonSize.cx*3,0,SRCCOPY);
mydc->StretchBlt(0,0, lpDrawItemStruct->rcItem.right-lpDrawItemStruct->rcItem.left,
lpDrawItemStruct->rcItem.bottom-lpDrawItemStruct->rcItem.top,
pMemDC,m_ButtonSize.cx*3,0, m_ButtonSize.cx,m_ButtonSize.cy, SRCCOPY );
}
}
}
if (lpDrawItemStruct->itemAction & ODA_FOCUS)
{
RECT rcFocus;
int iChange = 3;
rcFocus.top = lpDrawItemStruct->rcItem.top + iChange;
rcFocus.left = lpDrawItemStruct->rcItem.left + iChange;
rcFocus.right = lpDrawItemStruct->rcItem.right - iChange;
rcFocus.bottom = lpDrawItemStruct->rcItem.bottom - iChange;
pMemDC->DrawFocusRect(&rcFocus);
}
// clean up
pMemDC -> SelectObject(pOldBitmap);
delete pMemDC;
}
Что происходит, когда диалоговое окно является активным окном, и я нажимаю клавишу Tab один раз, фокусокно переходит ко второй кнопке, хотя я могу подтвердить с помощью обработчика нажатия кнопки, что первая кнопка имеет реальный фокус.Затем, когда я снова нажимаю клавишу Tab, окно фокусировки переходит, чтобы включить обе кнопки.Затем другое нажатие вкладки перемещает блок фокусировки на другую кнопку, и, наконец, другое нажатие вкладки полностью удаляет блок фокусировки.Эта последовательность происходитДаже удержание Shift-Tab не повлияет на это.
Я прослушал сообщения Windows, используя spy ++, и это выглядит довольно нормально.Я получаю сообщение WM_DRAWITEM для обеих кнопок управления, и они успешно обрабатываются.
Я упомяну одну последнюю вещь;в моем диалоговом коде, когда я инициализирую кнопки, я вынужден разместить кнопки внизу z-порядка, иначе IDC_STATIC_BKGND будет рисовать поверх кнопок.Это не казалось мне нормальным, потому что они уже должны быть в нижней части z-порядка.(Просто добавьте его на случай, если это является частью причины моей проблемы).
m_button1.SetHorizontal(true);
m_button1.SetMoveable(FALSE);
m_button1.LoadBitmap(IDB_BUTTON_1);
m_button1.SetToolTipText(_T("Some Text1"));
// Draws the button after the background is drawn
m_button1.SetWindowPos(&CWnd::wndBottom, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE);
m_button2.SetHorizontal(true);
m_button2.SetMoveable(FALSE);
m_button2.LoadBitmap(IDB_BUTTON_2);
m_button2.SetToolTipText(_T("Some Text2"));
// Draws the button after the background is drawn
m_button2.SetWindowPos(&CWnd::wndBottom, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE);
Кто-нибудь знает, как правильно добавить поле фокусировки для моей ситуации?
Спасибо.
Обновление: Попробовав предложение BrendanMcK и не решив проблему, я покопался еще в перехваченных сообщениях в spy ++ и заметил нечто, похожее на странное поведение.Следующие сообщения представляют собой нажатие одной вкладки в диалоговом окне.
<00283> 00870794 R WM_CTLCOLORBTN hBrush:01900015
<00284> 00870794 S WM_DRAWITEM idCtl:112 lpdis:002AEF2C
<00285> 00870794 R WM_DRAWITEM fProcessed:True
<00286> 00870794 S DM_GETDEFID
<00287> 00870794 R DM_GETDEFID wHasDef:DC_HASDEFID wDefID:0001
<00288> 00870794 S WM_CTLCOLORBTN hdcButton:110114A7 hwndButton:01090502
<00289> 00870794 R WM_CTLCOLORBTN hBrush:01900015
<00290> 00870794 S WM_DRAWITEM idCtl:113 lpdis:002AF2A0
<00291> 00870794 R WM_DRAWITEM fProcessed:True
Как видно, доставлено два отдельных сообщения WM_DRAWITEM.Подробности для каждого сообщения:
Сообщение № 284: действие = ODA_FOCUS, состояние = 0x0110 (ODS_FOCUS = 0x0010)
Сообщение № 290: действие = ODA_DRAWENTIRE, состояние = ODS_NOACCEL
Я бы ожидал, что в сообщении № 290 действие снова будет ODA_FOCUS, чтобы позволить другой кнопке «отрисовать» поле фокуса.
Я не уверен, почему я даже получаю состояние ODS_NOACCEL, поскольку я использую Win7.Я что-то забыл отключить?