Click here to Skip to main content
15,868,016 members
Articles / Programming Languages / C++
Article

Custom Event Handler for a Dynamically Created Control Embedded in Another Control

Rate me:
Please Sign up or sign in to vote.
4.09/5 (17 votes)
13 Jan 20062 min read 64.8K   1.2K   29   6
A simple way to trap a command message and send the message to any window.

Overview

Message Map Mechanism is the backbone of Event-Driven programming. In the MFC framework, DECLARE_MESSAGE_MAP(), BEGIN_MESSAGE_MAP(), and END_MESSAGE_MAP() are the three macros which create the road map of messages. Please refer to MSDN articles to get a better perception of what is happening inside these three macros. With this understanding, it would be pretty simple to write a custom message handler for a control that is into some other control.

I have chosen a dialog based application using MFC to demonstrate this. Inserting a MSHFlexGrid control, I have added buttons and checkboxes into the cells of the flex grid. The button clicked (BN_CLICKED) event has been trapped in my sample application but one could easily add other events also, following these steps.

In a dialog based MFC application, if you insert a Microsoft Hierarchical Flex Grid control, the framework will automatically add wrapper classes to invoke public methods of the control class. Now, if we wish to insert buttons in each row of column zero of the flex grid, which will appear at run-time, we have to insert the following code inside the OnInitDialog() function of the dialog class. Before doing so, add two pointers of CButton as private data members of the main dialog class, i.e., the CDynMsgMapDlg class in our example (CButton *m_pCheckBox, *m_pButtons).

OnInitDialog()

BOOL CDynMsgMapDlg::OnInitDialog()
{
    CDialog::OnInitDialog();

    // Add "About..." menu item to system menu.

    // IDM_ABOUTBOX must be in the system command range.
    ASSERT((IDM_ABOUTBOX & 0xFFF0) == IDM_ABOUTBOX);
    ASSERT(IDM_ABOUTBOX < 0xF000);

    ..............................
    ..............................
    // TODO: Add extra initialization here

    // Get Number of Rows of FlexGrid
    int nRow = m_hflexgrid.GetRows();

    // Create Button and CheckBox objects
    m_pButtons  = new CButton[m_hflexgrid.GetRows()];
    m_pCheckBox = new CButton[m_hflexgrid.GetRows()];

    for(int iCnt = 1; iCnt<nRow; iCnt++)
    {
        // Get Coordinates and Width,Height of flexgrid cells
        int nY     = m_hflexgrid.GetRowPos(iCnt);
        int nH     = m_hflexgrid.GetRowHeight(iCnt);
        
        // Get X-Coordinate and Width of flexgrid column number ZERO
        int nXBt = m_hflexgrid.GetColPos(0);
        int nWBt = m_hflexgrid.GetColWidth(0,0);

        // Get X-Coordinate and Width of flexgrid column number TWO
        int nXCb = m_hflexgrid.GetColPos(2);
        int nWCb = m_hflexgrid.GetColWidth(2,0);

        
        // Get the Grid Rectangle 
        CRect rectButton(nXBt/15, nY/15, (nXBt+nWBt)/15, (nY+nH)/15);
        // Get the Grid Rectangle 
        CRect rectCheckBox(nXCb/15, nY/15, (nXCb+nWCb)/15, (nY+nH)/15);

        CString cstrTextBt;
        cstrTextBt.Format("Button %d ",iCnt);
        // Create Button Dynamically Into the rectangle (Row=iCnt,Col=0)
        m_pButtons[iCnt].Create(
                     cstrTextBt, WS_CHILD|BS_PUSHBUTTON|WS_VISIBLE, 
                     rectButton, GetDlgItem(IDC_MSHFLEXGRID_TEST), 
                     iCnt+IDC_BUTTON_FIRST
                     );

        CString cstrTextCb;
        cstrTextCb.Format("CheckBox %d ",iCnt);
        // Create Button Dynamically Into the rectangle (Row=iCnt,Col=2)
        m_pCheckBox[iCnt].Create(
                     cstrTextCb, WS_CHILD|BS_AUTOCHECKBOX|WS_VISIBLE, 
                     rectCheckBox, GetDlgItem(IDC_MSHFLEXGRID_TEST), 
                     iCnt+IDC_CHECKBOX_FIRST
                      );

    }
    
    return TRUE;  // return TRUE  unless you set the focus to a control
}

With this, you will be able to see a button and a checkbox array populated in the zero'th and the second column of the grid.

Image 1

Now, we have to add a click event handler for the buttons we have already created. For this, you have to add a macro ON_CONTROL_RANGE() within the ClassWizard generated BEGIN_MESSAGE_MAP() and END_MESSAGE_MAP(). Here is our code snippet:

BEGIN_MESSAGE_MAP(CDynMsgMapDlg, CDialog)
//{{AFX_MSG_MAP(CDynMsgMapDlg)
  ON_WM_SYSCOMMAND()
  ON_WM_PAINT()
  ON_WM_QUERYDRAGICON()
  ON_WM_DESTROY()
//}}AFX_MSG_MAP
ON_CONTROL_RANGE(BN_CLICKED,IDC_BUTTON_FIRST, 
            IDC_BUTTON_LAST, OnButtonClicked)
END_MESSAGE_MAP()

Now, add the OnButtonClicked() prototype within the class declaration.

afx_msg void OnButtonClicked(UINT nIDbutton);

The implementation of OnButtonClicked() may be like:

void CDynMsgMapDlg::OnButtonClicked(UINT nIDbutton)
{
     MessageBox("BN_CLICKED Event trapped within  'MessageMap' Dialog");
}

After doing the steps up to this, if we try to run our application, we will see that a message box is not coming with the click event of the dynamically created buttons. The reason behind it is the dynamic creation of the buttons. As buttons and checkboxes have taken the MSHFlexGrid as their parent, the BN_CLICKED message has to be trapped within the wrapper class of MSHFlexGrid. So, add DECLARE_MESSAGE_MAP(), BEGIN_MESSAGE_MAP(), and END_MESSAGE_MAP() to trap the BN_CLICKED event as we did earlier. Now, the last thing is we have to send a WM_COMMAND message to the parent window of the MSHFlexGrid, i.e., the main dialog window with the same ID.

BEGIN_MESSAGE_MAP(CMSHFlexGrid, CWnd)
    //{{AFX_MSG_MAP(CMSHFlexGrid)
    //}}AFX_MSG_MAP
    ON_CONTROL_RANGE(BN_CLICKED,IDC_BUTTON_FIRST, 
                IDC_BUTTON_LAST, OnButtonClicked)
END_MESSAGE_MAP()

// Button Click Event handler : Post this message as WM_COMMAND message
// to the parent window, i.e. the Dialog containing flexgrid
void CMSHFlexGrid::OnButtonClicked(UINT nID)
{
    GetParent()->SendMessage(
                                WM_COMMAND,
                                MAKELONG(nID,BN_CLICKED),
                                (LPARAM)(GetDlgItem(nID)->m_hWnd)
                            );
}

Finally, add the OnScroll() event of the MSHFlexGrid using the ClassWizard, and insert the following code into it:

C++
void CDynMsgMapDlg::OnScrollMshflexgridTest() 
{
    // TODO: Add your control notification handler code here
    int nRow = m_hflexgrid.GetRows();
    int nTopRow = m_hflexgrid.GetTopRow();
    for(int iCnt = m_hflexgrid.GetFixedRows(); iCnt<nRow; iCnt++)
    {
        if(iCnt<nTopRow)
        {
            m_pButtons[iCnt].ShowWindow(SW_HIDE);
            m_pCheckBox[iCnt].ShowWindow(SW_HIDE);
        }
        else
        {
            // Get Coordinates and Width,Height of flexgrid cells
            int nY     = m_hflexgrid.GetRowPos(iCnt);
            int nH     = m_hflexgrid.GetRowHeight(iCnt);
            
            // Get X-Coordinate and Width of flexgrid column number ZERO
            int nXBt = m_hflexgrid.GetColPos(0);
            int nWBt = m_hflexgrid.GetColWidth(0,0);
            
            // Get X-Coordinate and Width of flexgrid column number TWO
            int nXCb = m_hflexgrid.GetColPos(2);
            int nWCb = m_hflexgrid.GetColWidth(2,0);
            
            
            // Get the Grid Rectangle 
            CRect rectButton(nXBt/15, nY/15, (nXBt+nWBt)/15, (nY+nH)/15);
            // Get the Grid Rectangle 
            CRect rectCheckBox(nXCb/15, nY/15, (nXCb+nWCb)/15, (nY+nH)/15);
            
            // Move Buttons and CheckBoxes along with the ScrollBar
            m_pButtons[iCnt].MoveWindow(rectButton);
            m_pButtons[iCnt].ShowWindow(SW_SHOW);
            m_pCheckBox[iCnt].MoveWindow(rectCheckBox);
            m_pCheckBox[iCnt].ShowWindow(SW_SHOW);
            
        }
    }    
}

Now, run the application, click a button inside the grid, and you will see what you want.

Image 2

Image 3

We need to be careful about this:

  • The button and checkbox IDs should be unique.

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here


Written By
Web Developer
United States United States
Rajib is one of the many altruist guy working with Cognizant Technology Solution ... Smile | :)

Comments and Discussions

 
QuestionIs there a way to achieve same thing without altering Pin
yash358-Dec-17 1:44
yash358-Dec-17 1:44 
GeneralVery Good article Pin
Koushik Biswas31-Aug-09 6:04
Koushik Biswas31-Aug-09 6:04 
Questionthis nice article for flexgrid Pin
yogesh shrikhande11-Mar-07 22:18
yogesh shrikhande11-Mar-07 22:18 
QuestionExcellent and useful article..... Can you ( or anyone ) help with CEdit box problem ? Pin
cfilorux16-Jul-06 13:49
cfilorux16-Jul-06 13:49 
GeneralNice one Pin
world.wild.web16-Jan-06 18:26
world.wild.web16-Jan-06 18:26 
GeneralFantastic Pin
Mainak Saha15-Jan-06 22:34
Mainak Saha15-Jan-06 22:34 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.