Click here to Skip to main content
Click here to Skip to main content

Dynamic button function call: alternative for BEGIN_MESSAGE_MAP

, 18 Feb 2010
Rate this:
Please Sign up or sign in to vote.
This article discusses a trick to define/re-define a dynamic button's click event.

Screenshot - DynButtonGIF.gif

Introduction

This article is going to show another aspect of BEGIN_MESSAGE_MAP() provided in VC++ (MFC). A brief introduction about this: in MFC, whenever there is a need to make a button control dynamic, we often get hung up on the point of defining a map to link with the corresponding method for that button such that when that button is clicked, our method will get called. This article is going to show you a sample of code where I have created a dynamic button, which is mapped with a function as per the job selected by the radio buttons, rather than using a pre-defined map.

Background

As an MFC developer, you may already know that whenever you have to create an application in which buttons or controls are going to be created dynamically, you need to presume the constant (Resource_ID) for controls. You also have to specify the method corresponding to the map, like ON_COMMAND(RESOURCE_ID, methodName) in BEGIN_MESSAGE_MAP(). As a result, whenever the button is clicked, the corresponding method would get invoked.

However, for a more dynamic environment, we may need to find an alternative way in which we can redefine the click event when it is already specified.

As a .NET developer, you may also be aware of delegates, pointers to functions that play a significant role in defining a method for any event of a control. This article talks about a similar functionality for a non-.NET environment. For the time being, this functionality is defined for the button-click event only. This is achieved using the ON_COMMAND() aspect of MFC with a pre-defined message map. The message map is defined and assigned values based on the requirements of the control. In future, I'll try to cover other events of MFC so that it may become more flexible for all events.

Using the code

We use a trick here: just like BEGIN_MESSAGE_MAP(), information about ID and its corresponding method is collected and stored in a pre-defined map. The following code is used for the creation of the map containing the ID and the function pointers:

typedef void (CDynButtonDlg::*fn)(int i);
typedef std::map< UINT, fn > EventMessageMap;

Using this map type, we create a new variable. Here is the actual instance:

EventMessageMap msgMap;

Whenever we need to create a button dynamically, we'll make a corresponding entry in this map:

// To Create Dynamic Button with #define DYNAMIC_BUTTON_ID 123
m_btnDynamic.Create("Dynamic", WS_VISIBLE|WS_CHILD|BS_PUSHBUTTON, 
    CRect(100,150,200,200),this, DYNAMIC_BUTTON_ID);

// Make Entry in Map for this ID
msgMap[DYNAMIC_BUTTON_ID] = &CDynButtonDlg::Job1;

Now, our work of changing functions is simple. Whenever we wish to change the functionality of a function, we just need to do this:

// Make Entry in Map for this ID
msgMap[DYNAMIC_BUTTON_ID] = &CDynButtonDlg::Job2;

The only remaining question to be answered is, "How will this function be called when the button is clicked?" The answer is:

// OnCmdMsg is called when any command is fired
BOOL CDynButtonDlg::OnCmdMsg(UINT nID, int nCode, 
    void* pExtra, AFX_CMDHANDLERINFO* pHandlerInfo) 
{
    // Here we'll iterate our Map & call it's corresponding function.
    EventMessageMap::iterator itTrg = msgMap.find( nID );
    if(itTrg != msgMap.end())
    {
        fn btnM = msgMap[nID];
        this->*btnM)(5);
    }
    return CDialog::OnCmdMsg(nID, nCode, pExtra, pHandlerInfo);
}

I am not claiming that this is the only way to do this. Another way could be by putting conditions and call functions accordingly. I just found a new way to accomplish this task, so I am sharing it with all of you here.

What's next

I wish to make MFC events more flexible as delegates are in .NET. I'll wait for your valuable comments. I'll update this article if I could find more free time/issues.

Happy coding! Smile | :)

History

  • 21 June 2007 -- Original version posted.
  • 17 February 2010 -- Updated description.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

Share

About the Author

Sumit Kapoor
Software Developer (Senior)
India India
Working in Patni Computer Systems, Noida(INDIA). I like to work in C/C++ even from my school time & mostly worked using C++, VC++, COM.
 
I want to give something bigger than biggest to IT field. Try is going on.
 
I like to make friends.
That’s all about me.
 
Ok! See you.
Have a nice Life.

Comments and Discussions

 
GeneralMy vote of 3 PinmemberMember 102364872-Feb-14 23:13 
QuestionCan I use message mapping of external windows applications Pinmemberstaler.ideas14-Jul-11 22:05 
Generalthis->*btnM)(5); PinmemberCODEPC19-Feb-10 2:19 
GeneralRe: this->*btnM)(5); Pinmemberfirehore_00730-Jun-11 4:08 
GeneralIt's good Pinmemberramcse11-Apr-08 11:35 
GeneralRe: It's good PinmemberSumit Kapoor13-Apr-08 23:38 
GeneralIt's helpful! PinmemberJames Huo27-Jan-08 14:48 
GeneralThis is great!! Pinmemberpointer29-Aug-07 3:23 
GeneralWell done Pinmemberwu27612010-Aug-07 18:58 
GeneralHOHO Pinmemberdesk11185-Aug-07 22:08 
GeneralGreat job Pinmemberbutchi peddi24-Jun-07 18:35 

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

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

| Advertise | Privacy | Mobile
Web02 | 2.8.140827.1 | Last Updated 18 Feb 2010
Article Copyright 2007 by Sumit Kapoor
Everything else Copyright © CodeProject, 1999-2014
Terms of Service
Layout: fixed | fluid