Search code examples
c++mfcribbon

How to programmatically show dropdown-menu of ribbon button?


I have ribbon button with a set of sub-items added. Such items are displayed when the user clicks on the tiny arrow below the button. I'd like to display such dropdown-menu when the button itself is clicked. How can I do that?

My initial idea was to programmatically show the menu when the user clicks the button. I've been able to do the same on toolbars (here) but using a similar solution on ribbons creates an infinite recursion:

// ...
ON_COMMAND(ID_RIBBON_BUTTON, &MainFrame::OnButtonClicked)
// ...

CMFCRibbonPanel *panel = /* initialization */
CMFCRibbonButton *button = new CMFCRibbonButton(ID_RIBBON_BUTTON, "Caption");
panel->Add(button);

CMFCRibbonButton *item1 = new CMFCRibbonButton(ID_RIBBON_BUTTON, "Item 1");
button->AddSubItem(item1);
CMFCRibbonButton *item2 = new CMFCRibbonButton(ID_RIBBON_BUTTON, "Item 2");
button->AddSubItem(item2);

// ...
void MainFrame::OnButtonClicked()
{
  if (auto button = static_cast<CMFCRibbonButton *>(m_ribbons.wndRibbonBar.FindByID(ID_RIBBON_BUTTON))) {

    // button->OnClick({}); // <- causes infinite recursion

    // What to do here?
  }
}

Solution

  • The easiest way I've found so far is to use the protected method CMFCRibbonButton::OnShowPopupMenu. It implies deriving the CMFCRibbonButton class and changing the visibility of the method:

    #include <afxribbonbutton.h>
    
    class CMyMFCRibbonButton : public CMFCRibbonButton {
    public:
      using CMFCRibbonButton::CMFCRibbonButton;
    
      virtual void OnShowPopupMenu() override {
        CMFCRibbonButton::OnShowPopupMenu();
      }
    };
    
    // ...
    ON_COMMAND(ID_RIBBON_BUTTON, &MainFrame::OnButtonClicked)
    // ...
    
    CMFCRibbonPanel *panel = /* initialization */
    CMyMFCRibbonButton *button = new CMyMFCRibbonButton(ID_RIBBON_BUTTON, "Caption");
    panel->Add(button);
    
    CMFCRibbonButton *item1 = new CMFCRibbonButton(ID_RIBBON_BUTTON, "Item 1");
    button->AddSubItem(item1);
    CMFCRibbonButton *item2 = new CMFCRibbonButton(ID_RIBBON_BUTTON, "Item 2");
    button->AddSubItem(item2);
    
    // ...
    void MainFrame::OnButtonClicked()
    {
      if (auto button = static_cast<CMyMFCRibbonButton*>(m_ribbons.wndRibbonBar.FindByID(ID_RIBBON_BUTTON))) {
        button->OnShowPopupMenu();
      }
    }