【问题标题】:MFC: CMFCDropDownToolBar is blank for all but the first one buttonMFC:CMFCDropDownToolBar 除第一个按钮外的所有按钮均为空白
【发布时间】:2020-09-04 07:23:58
【问题描述】:

CMainFrame::OnCreate中创建了CMFCDropDownToolBar

// 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, 0, 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() 调用手动添加的按钮之一时,主工具栏上的按钮为空白且没有工具提示.如果我然后返回并选择第一个按钮(已加载资源的一部分),它会显示正确的图标和工具提示。

我做错了什么?

谢谢!!

【问题讨论】:

    标签: winapi mfc cmfctoolbar


    【解决方案1】:

    问题是CMFCDropDownToolbarButton::SetDefaultCommand(UINT uiCmd) 有缺陷。如果不是bUserButton 类型,则假定m_ImagesLocked 的索引是按位置而不是使用按钮iIndex。您不能使用bUserButton 并支持bLargeButtons,因为用户按钮的大小必须相同。此外,位于主工具栏上的按钮采用第一项 m_strText (通常是空字符串,因为已加载工具栏),因此通过上面的 CMainFrame::GetToolbarButtonToolTipText() 更新的工具提示也不起作用(它应该拉入按钮文本但没有't)。所以可能测试最好的办法是把afxdropdowntoolbar.cpp 复制到项目中,然后用一个新的类名修复它。有点代码膨胀,如果SetDefaultCommand() 是虚拟的,就可以轻松修复它。

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


    让一切都按照它应该开始的方式工作,如果你需要这个,这里是核心更改:

    呃,需要覆盖受保护的 CMFCToolBarImages::CopyTemp() 所以我不需要重做几乎所有的 MFC 工具栏支持,而是添加了这个 hack!我没有添加任何数据成员,所以应该保持与 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, SDI frame...
        {
            CFrameWndEx* pFrame = DYNAMIC_DOWNCAST(CFrameWndEx, pTopFrame);
            if (pFrame != NULL)
            {
              pFrame->GetMessageString(nID, rMessage);
          return;
            }
            else // Maybe, MDIChild frame
            {
                CMDIChildWndEx* pMDIChild = DYNAMIC_DOWNCAST(CMDIChildWndEx, pTopFrame);
    
                if (pMDIChild != NULL)
                {
                pMDIChild->GetMessageString(nID, rMessage);
            return;
                }
                else // Maybe, OLE frame...
                {
                    COleIPFrameWndEx* pOleFrame = DYNAMIC_DOWNCAST(COleIPFrameWndEx, 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);
      */
    
      .
      .
      .
     };
    

    【讨论】:

    猜你喜欢
    • 2023-03-30
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-01-05
    • 1970-01-01
    相关资源
    最近更新 更多