0

I found an article online that said to setup the toolbar button to be a type that stays pressed you just set a style TBBS_CHECKBOX on the button but it doesn't work for me (it still acts like a normal button). I confirmed the style is set, just after created and the SetWindowText() MFC wizard setup of CMainFrame::OnCreate(). What am I doing wrong?

 for (int i=0; ; i++) {
    int id=m_wndToolBar.GetItemID(i);
    if (id==0) {
      break;
    }
    if (id == ID_THE_ID) {
      m_wndToolBar.SetButtonStyle(i, TBBS_CHECKBOX);
    }
  }
df234987
  • 513
  • 2
  • 13
  • Please provide a [mcve]. – IInspectable Jun 11 '20 at 06:34
  • It could be useful if you post a link to that article. – Jabberwocky Jun 11 '20 at 12:23
  • 2
    The recommended implementation is to utilize the [UI Update Mechanism](https://learn.microsoft.com/en-us/cpp/mfc/how-to-update-user-interface-objects?view=vs-2019) instead. The `ON_COMMAND` handler should toggle a boolean variable, and the `ON_UPDATE_COMMAND_UI` one update the item(s) accordingly. See some tips in my post [here](https://stackoverflow.com/questions/40864274/mfc-menu-item-remains-grayed/40873304#40873304). – Constantine Georgiou Jun 11 '20 at 12:35
  • That was good info, but what about the keeping pressed when active, does command ui only offer enable/disable or can also set the state? It will be a filter button (picture of funnel on it) where it's either active or not active. – df234987 Jun 11 '20 at 21:58

1 Answers1

2

Using Command Handlers is the recommended implementation here. A command ID may be used in multiple UI items, eg a menu item and a toolbar button. A handler affects all items with the same ID, so you don't need a separate one for each item. The CCmdUI Class provides methods that can cause UI items like menus or toolbar buttons to behave as push-buttons, check-boxes or radio-buttons, in addition to enabling/disabling.

In your example, suppose that the option whether to filter is instantiated on a per document basis, ie all views of the document would be filtered or non-filtered, all at the same time. You should define a boolean variable in your document class:

BOOL m_bFilterData = FALSE;

Then the ON_COMMAND and ON_UPDATE_COMMAND_UI handlers for the toolbar button with the Filter pic (and possibly a menu item as well):

BEGIN_MESSAGE_MAP(CMyDoc, CDocument)
  .
  .
    ON_COMMAND(ID_VIEW_FILTERDATA, OnViewFilterData)
    ON_UPDATE_COMMAND_UI(ID_VIEW_FILTERDATA, OnUpdateViewFilterData)
  .
  .
END_MESSAGE_MAP()

void CMyDoc::OnViewFilterData()
{
    // Toggle filtered state
    m_bFilterData = !m_bFilterData;
    // Tell all views to refresh - You can limit this using the lHint/pHint params 
    UpdateAllViews(NULL, 0L, NULL);
}

void CMyDoc::OnUpdateViewFilterData(CCmdUI* pCmdUI)
{
    // Enable/Disable as needed
    pCmdUI->Enable(m_nTotalItems>0);
    // Show pressed/checked if data filtered
    pCmdUI->SetCheck(m_bFilterData);
}

Now, if the filter option is instantiated per view, ie each view can indpendently be filtered or non-filtered, the above must go to your view class(-es):

void CMyView::OnViewFilterData()
{
    // Toggle filtered state
    m_bFilterData = !m_bFilterData;
    // Refresh this view only
    .
    .
}

void CMyView::OnUpdateViewFilterData(CCmdUI* pCmdUI)
{
    // Enable/Disable as needed
    pCmdUI->Enable(GetDocument()->m_nTotalItems > 0);
    // Show pressed/checked if data filtered
    pCmdUI->SetCheck(m_bFilterData);
}
Constantine Georgiou
  • 2,412
  • 1
  • 13
  • 17
  • Perfect, now it all makes sense. Would you mind taking a peek at https://stackoverflow.com/questions/62334917/mfc-how-do-you-get-cmfctoolbarcomboboxbutton-to-show-on-a-cmfctoolbar too? – df234987 Jun 12 '20 at 04:30