MFC:CMFCDropDownToolBar除第一个按钮外,其他所有按钮均为空白

问题描述

CMFCDropDownToolBar中创建了CMainFrame::OnCreate

// Loading toolbar with a single icon/entry.
if (!m_wndMyDropdownToolBar.Create(this,WS_CHILD|CBRS_TOP|CBRS_TOOLTIPS|CBRS_FLYBY|CBRS_HIDE_INPLACE|CBRS_SIZE_DYNAMIC|   
    CBRS_GRIPPER | CBRS_BORDER_3D,ID_ACTION_BUTTON) ||    
    !m_wndMyDropdownToolBar.LoadToolBar (IDR_TOOLBAR_DROPDOWNSELECT))   
{   
    TRACE0("Failed to create build toolbar\n");   
    return FALSE;      // fail to create   
}   

// build list - use existing icon
for (UINT i=0; i<2; i++) {
  CString s;
  s.Format(_T("%i: Whatever %i\n"),i,i);
  m_wndMyDropdownToolBar.InsertButton(CMFCToolBarButton(ID_COMMAND_START+i,s));
};

然后休息:

afx_msg LRESULT CMainFrame::OnToolbarReset(WPARAM idtoolbar,LPARAM)
{
  if (idtoolbar==IDR_MAINFRAME) {
    ASSERT(m_wndMyDropdownToolBar.GetSafeHwnd() != NULL);

     //-----------------------------------   
     // Replace dropdown button:   
     //-----------------------------------   
    m_wndToolBar.ReplaceButton(ID_ACTION_BUTTON_DUMMY,CMFCDropDownToolbarButton(_T("Text that doesn't show anywhere"),&m_wndMyDropdownToolBar));
  }

  return 0;
}


BOOL CMainFrame::GetToolbarButtonToolTipText(CMFCToolBarButton* pButton,CString& strTTText)
{
  if (pButton->m_nID>=ID_COMMAND_START && pButton->m_nID<=ID_COMMAND_END) {
    // use text
    strTTText=pButton->m_strText;
    return TRUE;
  }
  return FALSE;
}   

只要下拉菜单显示按钮,鼠标悬停显示工具提示,一切正常,但是当您选择通过InsertButton()调用手动添加的按钮之一时,主工具栏上的按钮为空白,没有工具提示。如果我然后返回并选择第一个按钮(已加载资源的一部分),它将显示正确的图标和工具提示。

我在做什么不正确?

谢谢!

解决方法

问题是CMFCDropDownToolbarButton::SetDefaultCommand(UINT uiCmd)有缺陷。如果不是bUserButton类型,那么它将假定m_ImagesLocked的索引是按位置而不是按按钮iIndex的。您不能使用bUserButton来支持bLargeButtons,因为用户按钮的大小必须相同。另外,位于主工具栏上的按钮将显示第一个项m_strText(自从加载工具栏以来通常为空字符串),因此通过上面的CMainFrame::GetToolbarButtonToolTipText()进行的工具提示更新也不起作用(它应拉入按钮发短信,但不发短信)。因此,可能最好的测试方法是使用afxdropdowntoolbar.cpp并将其复制到项目中,然后使用新的类名对其进行修复。如果只有SetDefaultCommand()是虚拟的,那么一点代码膨胀就可以轻松解决。

还请注意,如果使用LoadBitmap / LoadBitmapEx,则应将bLocked设置为TRUE(以及使用InsertButton()时)


一切正常,如果需要的话,这是核心更改:

哎呀,需要重写受保护的CMFCToolBarImages :: CopyTemp(),因此不必重做几乎所有的MFC工具栏支持,我添加了这个技巧!我没有添加任何数据成员,因此应保持与CMFCToolBar的兼容性。

class CMyToolBarImages : public CMFCToolBarImages
{
  public:

  void MyCopyTemp(CMyToolBarImages *imagesDest) const
  {
      imagesDest->Clear();
      imagesDest->m_bIsTemporary = TRUE;

      imagesDest->m_sizeImage = m_sizeImage;
      imagesDest->m_sizeImageDest = m_sizeImageDest;
      imagesDest->m_hbmImageWell = m_hbmImageWell;
      imagesDest->m_bUserImagesList = m_bUserImagesList;
      imagesDest->m_iCount = m_iCount;
      imagesDest->m_bReadOnly = TRUE;
      imagesDest->m_nBitsPerPixel = m_nBitsPerPixel;
  }
};

class CMyDropDownToolBar : public CMFCToolBar
{
   .
   .
   .
   
  virtual BOOL OnUserToolTip(CMFCToolBarButton* pButton,CString& strTTText) const;

  // HACK protected CMFCToolBarImages!!
  void CopyTempAll(CMyDropDownToolBar *desttoolbar) const
  {
    ((const CMyToolBarImages*) &m_ImagesLocked)->MyCopyTemp((CMyToolBarImages*) &desttoolbar->m_ImagesLocked);
    ((const CMyToolBarImages*) &m_ColdImagesLocked)->MyCopyTemp((CMyToolBarImages*) &desttoolbar->m_ColdImagesLocked);
    ((const CMyToolBarImages*) &m_DisabledImagesLocked)->MyCopyTemp((CMyToolBarImages*) &desttoolbar->m_DisabledImagesLocked);
    ((const CMyToolBarImages*) &m_LargeImagesLocked)->MyCopyTemp((CMyToolBarImages*) &desttoolbar->m_LargeImagesLocked);
    ((const CMyToolBarImages*) &m_LargeColdImagesLocked)->MyCopyTemp((CMyToolBarImages*) &desttoolbar->m_LargeColdImagesLocked);
    ((const CMyToolBarImages*) &m_LargeDisabledImagesLocked)->MyCopyTemp((CMyToolBarImages*) &desttoolbar->m_LargeDisabledImagesLocked);
  }
};

已调用CMainFrame作为工具提示:

BOOL CMyDropDownToolBar::OnUserToolTip(CMFCToolBarButton* pButton,CString& strTTText) const
{
    ASSERT_VALID(pButton);

    CFrameWnd* pTopFrame = AFXGetParentFrame(this);
    if (pTopFrame == NULL)
    {
        return FALSE;
    }

    CMyDropDownFrame* pDropFrame = DYNAMIC_DOWNCAST(CMyDropDownFrame,pTopFrame);
    if (pDropFrame != NULL)
    {
        pTopFrame = AFXGetParentFrame(pDropFrame);
        if (pTopFrame == NULL)
        {
            return FALSE;
        }
    }

    CMDIFrameWndEx* pMainFrame = DYNAMIC_DOWNCAST(CMDIFrameWndEx,pTopFrame);
    if (pMainFrame != NULL)
    {
        return pMainFrame->GetToolbarButtonToolTipText(pButton,strTTText);
    }
    else // Maybe,SDI frame...
    {
        CFrameWndEx* pFrame = DYNAMIC_DOWNCAST(CFrameWndEx,pTopFrame);
        if (pFrame != NULL)
        {
            return pFrame->GetToolbarButtonToolTipText(pButton,strTTText);
        }
        else // Maybe,MDIChild frame
        {
            CMDIChildWndEx* pMDIChild = DYNAMIC_DOWNCAST(CMDIChildWndEx,pTopFrame);

            if (pMDIChild != NULL)
            {
                return pMDIChild->GetToolbarButtonToolTipText(pButton,strTTText);
            }
            else // Maybe,OLE frame...
            {
                COleIPFrameWndEx* pOleFrame = DYNAMIC_DOWNCAST(COleIPFrameWndEx,pFrame);
                if (pOleFrame != NULL)
                {
                    return pOleFrame->GetToolbarButtonToolTipText(pButton,strTTText);
                }
            }
        }
    }

    return FALSE;

}

对于启动整个过程所需的实际第一个修复程序:

void CMyDropDownToolbarButton::SetDefaultCommand(UINT uiCmd)
{
  .
  .
  .

        if (pButton->m_nID == uiCmd)
        {
            m_bLocalUserButton = pButton->m_bUserButton;

            if (m_bLocalUserButton)
            {
                m_iSelectedImage = pButton->GetImage();
            }
            else
            {
                // FIXED HERE:
                m_iSelectedImage=pButton->GetImage();
                if (m_iSelectedImage==-1) {
                    m_iSelectedImage=iImage;
                }
            }
            // FIXED HERE:
            m_strText=pButton->m_strText;
            break;
        }

  .
  .
  .
}

要使工具提示看起来与粗体和普通字体一致,请使用CMainFrame :: GetMessageString:

class CMyDropDownFrame : public CMiniFrameWnd
{
   .
   .
   .
   
   // For customizing the default messages on the status bar and second line of tooltip
   virtual void GetMessageString(UINT nID,CString& rMessage) const;
};


// For customizing the default messages on the status bar and second line of tooltip
void CMyDropDownFrame::GetMessageString(UINT nID,CString& rMessage) const
{
    CFrameWnd* pTopFrame = AFXGetParentFrame(this);
    if (pTopFrame == NULL)
    {
        return;
    }

    CMFCDropDownFrame* pDropFrame = DYNAMIC_DOWNCAST(CMFCDropDownFrame,pTopFrame);
    if (pDropFrame != NULL)
    {
        pTopFrame = AFXGetParentFrame(pDropFrame);
        if (pTopFrame == NULL)
        {
            return;
        }
    }

    CMDIFrameWndEx* pMainFrame = DYNAMIC_DOWNCAST(CMDIFrameWndEx,pTopFrame);
    if (pMainFrame != NULL)
    {
        pMainFrame->GetMessageString(nID,rMessage);
    return;
    }
    else // Maybe,pTopFrame);
        if (pFrame != NULL)
        {
          pFrame->GetMessageString(nID,rMessage);
      return;
        }
        else // Maybe,pTopFrame);

            if (pMDIChild != NULL)
            {
            pMDIChild->GetMessageString(nID,rMessage);
        return;
            }
            else // Maybe,pFrame);
                if (pOleFrame != NULL)
                {
              pOleFrame->GetMessageString(nID,rMessage);
          return;
                }
            }
        }
    }
}

还需要更改CMyDropDownFrame :: OnCreate()以处理保护成员:

int CMyDropDownFrame::OnCreate(LPCREATESTRUCT lpCreateStruct)
{
  .
  .
  .
  
    // "Clone" the original toolbar:
  m_pWndOriginToolbar->CopyTempAll(&m_wndToolBar);
  /*
    m_pWndOriginToolbar->m_ImagesLocked.CopyTemp(m_wndToolBar.m_ImagesLocked);
    m_pWndOriginToolbar->m_ColdImagesLocked.CopyTemp(m_wndToolBar.m_ColdImagesLocked);
    m_pWndOriginToolbar->m_DisabledImagesLocked.CopyTemp(m_wndToolBar.m_DisabledImagesLocked);
    m_pWndOriginToolbar->m_LargeImagesLocked.CopyTemp(m_wndToolBar.m_LargeImagesLocked);
    m_pWndOriginToolbar->m_LargeColdImagesLocked.CopyTemp(m_wndToolBar.m_LargeColdImagesLocked);
    m_pWndOriginToolbar->m_LargeDisabledImagesLocked.CopyTemp(m_wndToolBar.m_LargeDisabledImagesLocked);
  */

  .
  .
  .
 };

相关问答

错误1:Request method ‘DELETE‘ not supported 错误还原:...
错误1:启动docker镜像时报错:Error response from daemon:...
错误1:private field ‘xxx‘ is never assigned 按Alt...
报错如下,通过源不能下载,最后警告pip需升级版本 Requirem...