自定义控制绘图 - 焦点状态

时间:2011-11-04 20:40:30

标签: c++ winapi mfc focus

我创建了两个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也不会影响它。

我用spy ++嗅出了windows消息,看起来很正常。我得到两个按钮控件的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的建议并且没有解决问题之后,我在间谍++中捕获的消息中挖掘了更多,并注意到一些看似奇怪的行为。以下消息表示对话框中的单个选项卡按下。

<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:action = ODA_FOCUS,state = 0x0110(ODS_FOCUS = 0x0010)

消息#290:action = ODA_DRAWENTIRE,state = ODS_NOACCEL

我原本预计在消息#290中,动作将再次为ODA_FOCUS以允许其他按钮“取消”绘制焦点框。

我不确定为什么我甚至会收到ODS_NOACCEL状态,因为我正在使用Win7。有没有我忘了禁用的东西?

1 个答案:

答案 0 :(得分:0)

来自MSDN on DRAWITEMSTATE

ODA_FOCUS 控件已丢失或获得键盘焦点。应检查itemState成员以确定控件是否具有焦点。

因为您正在重绘控件,所以如果itemState指示控件具有焦点,则应该只绘制焦点rect。相反,你是在所有情况下绘制它,关注控件是否获得或失去焦点。添加一个检查以查看itemState&amp; ODS_FOCUS,你应该很好。