Home > Mobile >  can you pass an argument to a windows on_bn_clicked function?
can you pass an argument to a windows on_bn_clicked function?

Time:01-30

I have a Windows GUI program (Visual Studio 2019) with many buttons that perform the same function but on a different device. Rather than have 20 different functions along the lines of:

BEGIN_MESSAGE_MAP(CChainDlg, CDialogEx)
    ON_BN_CLICKED   ( IDC_CHECK_1,  &CChainDlg::OnBnClickedCheck1 )
    ON_BN_CLICKED   ( IDC_CHECK_2,  &CChainDlg::OnBnClickedCheck2 )
    ON_BN_CLICKED   ( IDC_CHECK_3,  &CChainDlg::OnBnClickedCheck3 )
    ...
END_MESSAGE_MAP()
...
void CChainDlg::OnBnClickedCheck1() {...}
void CChainDlg::OnBnClickedCheck2() {...}
void CChainDlg::OnBnClickedCheck3() {...}

... each of which performs the same basic function only differing in an array index, I'd like to have one function that can accept an index.

The ON_BN_CLICKED macro does not want to take arguments which would seem like the most obvious way of accomplishing this. E.g.:

BEGIN_MESSAGE_MAP(CChainDlg, CDialogEx)
    ON_BN_CLICKED   ( IDC_CHECK_1,  &CChainDlg::OnBnClickedCheck(0) )
    ON_BN_CLICKED   ( IDC_CHECK_2,  &CChainDlg::OnBnClickedCheck(1) )
    ON_BN_CLICKED   ( IDC_CHECK_3,  &CChainDlg::OnBnClickedCheck(2) )
    ...
END_MESSAGE_MAP()

What I currently do is write the generic function that takes an argument and have the individual OnBnClickedCheck1() functions call the generic function with the correct argument. But that just seems messy.

Suggest to me a better way!

CodePudding user response:

To expand on Captain Obvlious's comment: You could use a template method:

class CChainDlg {
  BEGIN_MESSAGE_MAP(CChainDlg, CDialogEx)
    ON_BN_CLICKED   ( IDC_CHECK_1,  &CChainDlg::OnBnClickedCheck<1> )
    ON_BN_CLICKED   ( IDC_CHECK_2,  &CChainDlg::OnBnClickedCheck<2> )
    ON_BN_CLICKED   ( IDC_CHECK_3,  &CChainDlg::OnBnClickedCheck<3> )
    ...
  END_MESSAGE_MAP()

  template<size_t idx>
  void OnBnClickedCheck() {
    ... my_array[idx] ...
  }
}

CodePudding user response:

If your button control IDs are sequential in value, you can use the ON_CONTROL_RANGE() macro to map all of the controls to a single handler, eg:

BEGIN_MESSAGE_MAP(CChainDlg, CDialogEx)
    ON_CONTROL_RANGE( BN_CLICKED, IDC_CHECK_1, IDC_CHECK_3, &CChainDlg::OnBnClicked ) 
    ...
END_MESSAGE_MAP()
...
void CChainDlg::OnBnClicked(UINT nID) {...}

Now your handler can take a parameter that tells it which control triggered the notification.

This is described in more detail on MSDN:

Handlers for Message-Map Ranges

  • Related