C++ 自定义控件图形-焦点状态

C++ 自定义控件图形-焦点状态,c++,winapi,mfc,focus,C++,Winapi,Mfc,Focus,我已经创建了两个类实例,只做了一点修改,以包含一个禁用状态 这些按钮存在于包含以下属性的无模式对话框中: 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_BIT

我已经创建了两个类实例,只做了一点修改,以包含一个禁用状态

这些按钮存在于包含以下属性的无模式对话框中:

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键时,焦点框会跳到包含这两个按钮。然后另一次按tab键将焦点框移动到另一个按钮,最后另一次按tab键将焦点框完全移除。这个序列一直在发生。即使按住Shift Tab键也不会影响它

我用spy++嗅出了windows消息,看起来很正常。我收到两个按钮控件的WM_DRAWITEM消息,它们都被成功处理

我要提最后一件事;在我的对话框代码中,当我初始化按钮时,我被迫将按钮放在z顺序的底部,否则IDC_STATIC_BKGND会覆盖这些按钮。这在我看来并不正常,因为它们应该已经在z顺序的底部了。(只是加上它,以防它是我问题的一部分原因)

有人知道如何为我的情况正确添加焦点框吗

谢谢

更新: 在尝试了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
00870794 R WM_CTLCOLORBTN hBrush:01900015
00870794 S WM_图纸项目idCtl:112 lpdis:002AEF2C
00870794 R WM_DRAWITEM F已处理:真
00870794 S DM_GETDEFID
00870794 R DM_GETDEFID wHasDef:DC_HASDEFID wDefID:0001
00870794 S WM_CTLCOLORBTN HDC按钮:110114A7 hwndButton:01090502
00870794 R WM_CTLCOLORBTN hBrush:01900015
00870794 S WM_图纸项目编号:113 lpdis:002AF2A0
00870794 R WM_DRAWITEM F已处理:真
显然,有两个单独的WM_DRAWITEM消息被传递。每条信息的详细信息如下:

消息284:action=ODA_FOCUS,state=0x0110(ODS_FOCUS=0x0010)

消息#290:action=ODA#u抽屉,state=ODS#u NOACCEL

我本以为在信息290中,操作将再次是ODA#U焦点,以允许另一个按钮“取消绘制”焦点框

我不知道为什么我在使用Win7时会收到ODS_NOACCEL状态。有什么我忘记禁用的吗?

来自:

ODA_焦点 控件已失去或获得键盘焦点。应检查itemState成员以确定控件是否具有焦点。
因为您正在重新绘制控件,所以只有当itemState指示控件具有焦点时,才应该绘制focus rect。取而代之的是,你在所有情况下都在画它,考虑控制是获得焦点还是失去焦点。添加一项检查,查看itemState&ODS_是否关注,您应该表现良好。

谢谢您的建议,但运气不好。我在主帖子中添加了一个更新。
<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