MFC: CMFCDropDownToolBar пуст для всех, кроме одной первой кнопки

#winapi #mfc #cmfctoolbar

#winapi #мфц #cmfctoolbar #mfc

Вопрос:

Создал 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 toolbarn");   
    return FALSE;      // fail to create   
}   

// build list - use existing icon
for (UINT i=0; i<2; i  ) {
  CString s;
  s.Format(_T("%i: Whatever %in"), 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"), amp;m_wndMyDropdownToolBar));
  }

  return 0;
}


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

Все работает нормально, поскольку в выпадающем списке отображаются кнопки, при наведении курсора отображается всплывающая подсказка, но когда вы выбираете одну из кнопок, добавленных вручную с помощью InsertButton() вызова, кнопка на главной панели инструментов пуста и всплывающих подсказок нет. Если я затем вернусь и выберу первую кнопку (часть загруженного ресурса), она покажет правильный значок и подсказку.

Что я делаю неправильно?

Спасибо!!

Ответ №1:

Проблема в том, что 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, CStringamp; strTTText) const;

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

Вызовите CMainFrame для всплывающей подсказки:

 BOOL CMyDropDownToolBar::OnUserToolTip(CMFCToolBarButton* pButton, CStringamp; 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, CStringamp; rMessage) const;
};


// For customizing the default messages on the status bar and second line of tooltip
void CMyDropDownFrame::GetMessageString(UINT nID, CStringamp; 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(), чтобы иметь дело с участником protect:

 int CMyDropDownFrame::OnCreate(LPCREATESTRUCT lpCreateStruct)
{
  .
  .
  .
  
    // "Clone" the original toolbar:
  m_pWndOriginToolbar->CopyTempAll(amp;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. Привет @user3161924, спасибо, что поделились решением, и вы также можете принять свой собственный ответ .