Пользовательский элемент управления - состояние фокуса - PullRequest
0 голосов
/ 05 ноября 2011

Я создал два экземпляра класса 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.Я что-то забыл отключить?

1 Ответ

0 голосов
/ 05 ноября 2011

С MSDN на DRAWITEMSTATE :

ODA_FOCUS Элемент управления потерял или получил фокус клавиатуры.Элемент itemState должен быть проверен, чтобы определить, имеет ли элемент управления фокус.

Поскольку вы перерисовываете элемент управления, вы должны рисовать прямоугольник фокуса, только если itemState указывает, что элемент управления имеет фокус.Вместо этого вы рисуете его во всех случаях, независимо от того, получает ли элемент управления или теряет фокус.Добавьте проверку, чтобы увидеть, если itemState & ODS_FOCUS, и вы должны быть хорошими.

...