Click here to Skip to main content
15,881,938 members
Articles / Desktop Programming / MFC

Command routing beyond a split frame

Rate me:
Please Sign up or sign in to vote.
5.00/5 (9 votes)
16 Jul 2002CPOL3 min read 96.5K   34   15
Command routing and UI updates for inactive views in a split frame.

Abstract

The article presents three simple methods of routing WM_COMMAND messages through a number of views in a split frame window. This simplifies dealing with the command routing and UI updates for inactive views.

Introduction to the Problem

The standard framework route does not include inactive views, which causes toolbar buttons and menus to gray when their mother view is deactivated. Users are confused. I present three simple methods to bring their happiness back. :) All solutions base on overriding the CCmdTarget::OnCmdMsg function in the frame class. I assumed that this class is derived directly from CFrameWnd (SDI case), but these methods can be used with MDI child window as well.

In each case, the overridden function browses through a list of views and calls CCmdTarget::OnCmdMsg for each of them, passing the received arguments. If TRUE is returned, we can return – the message has undoubtedly been handled by the view and no further processing is needed. Naturally, the active view is excluded from this call, because it is to be processed by the base handler – this is the default case. You may place a base function call in the beginning of the overridden function body if you expect the messages to be successfully processed mostly by an active view, a frame itself or a CWinApp-derived object, as these three calls are made in the base CFrameWnd::OnCmdMsg implementation. Our custom routine should then be executed only if the base implementation returns FALSE.

Classic Document/View Case

The first quite obvious method is to use a list of views that is available in the CDocument class and accessible through the GetFirstViewPosition / GetNextView helper function pair. Along with the active view, this method browses all inactive ones, but you may filter the list as you wish to suit your application’s needs.

C++
BOOL CMainFrame::OnCmdMsg(UINT nID, int nCode, void* pExtra,
	AFX_CMDHANDLERINFO* pHandlerInfo) 
{
    CDocument *pDoc = GetActiveDocument();
    if(pDoc)
    {
	POSITION pos = pDoc->GetFirstViewPosition();
	CView *pView = NULL;
	while(pView = pDoc->GetNextView(pos))
	{
	    if(pView != GetActiveView()
		&& pView->OnCmdMsg(nID, nCode, pExtra, pHandlerInfo))
		return TRUE;
	}
    }

    return CFrameWnd::OnCmdMsg(nID, nCode, pExtra, pHandlerInfo);
}

Splitter Window Case

What if we didn’t like to use any CDocument-derived class object at all? This may be the case, and the first method would then be useless. Yet, to achieve the routing goal, we don’t need a document, as we only have to get access to windows that process the message, i.e. the splitter panes. This is no hassle if you have an explicit splitter object – either as a pointer, or as a member in your frame class, which I find a common case. Simply use CSplitterWnd::GetPane and have it done! This case has also been hinted by Samuel Chow some time ago.

C++
BOOL CMainFrame::OnCmdMsg(UINT nID, int nCode, void* pExtra,
        AFX_CMDHANDLERINFO* pHandlerInfo) {
    if(m_wndSplitter.GetSafeHwnd())
    {
        int rc = m_wndSplitter.GetRowCount(),
            cc = m_wndSplitter.GetColumnCount();

        for(int r = 0; r < rc; r++)
            for(int c = 0; c < cc; c++)
        {
                CWnd *pWnd = m_wndSplitter.GetPane(r, c);
                if(pWnd != m_wndSplitter.GetActivePane()
                    && pWnd->OnCmdMsg(nID, nCode, pExtra, pHandlerInfo))
                    return TRUE;
        }
    }
    return CFrameWnd::OnCmdMsg(nID, nCode, pExtra, pHandlerInfo); }

A Possibly Universal Case

A young eager mind would then like to have a universal handler, independent of existence of member splitters or even a document. Seeking inspiration in MFC sources, namely CView and CSplitterWnd classes, I noticed that they utilize standard pane IDs (see afxres.h) to get access to inactive views in a frame. And surely they use neither a document pointer, nor a splitter object directly! Now here comes the Holy Grail:

C++
BOOL CMainFrame::OnCmdMsg(UINT nID, int nCode, void* pExtra,
	AFX_CMDHANDLERINFO* pHandlerInfo) 
{
    for(UINT id = AFX_IDW_PANE_FIRST; id <= AFX_IDW_PANE_LAST; id++)
    {
	CWnd *pWnd = GetDescendantWindow(id, TRUE);
	if(pWnd && pWnd != GetActiveView()
	    && pWnd->OnCmdMsg(nID, nCode, pExtra, pHandlerInfo))
	    return TRUE;
	}
    }
    return CFrameWnd::OnCmdMsg(nID, nCode, pExtra, pHandlerInfo);
}

As with the first method, the handler doesn’t have to be called for all views, as the calls may be freely filtered. It may be even done dynamically, e.g. depending on nID or nCode values, but I’m afraid this would complicate the routing a bit too much. Such roundabout solutions should always be thought over twice – there are many straightforward methods of distributing the message handling among the existing command targets, and this is not the case.

There is no possibility that these snippets would solve all your trouble with MFC command message routing, but it may get you closer or simply bring you a little clue. Any comments and suggestions are warmly welcome.

License

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


Written By
CEO SPIN Software
Poland Poland
I am a software designer and developer. I build bridges!

I build bridges between reality and imagination (design and creation of video games, video game production tools):
• experience managing a technological team for almost 10 years (around 30 projects),
• co-created multiple video games for demanding hardware platforms,
• implemented game-like interaction and awarding systems in non-game applications to make them
enjoyable.

I build bridges between theory and visualization (design and creation of decision support systems):
• created an innovative tool for interconnecting various techniques of artificial intelligence,
• created multiple expert systems that were used for proving PhD theses, and then implemented in
the industry.

I build bridges between companies and people (design and creation of scientific, industrial and
business software):
• created multiple software packages in the field of civionics, including bridge management systems
and real-time measurement / data processing software,
• created and developed 7 large applications for business / state customers,
• created and sold first own C++ application back in 1996; after some upgrades it still serves its
commercial purpose for the client.

Projects with value up to $14M, ranging from complex industrial, business and scientific applications using highly customized MFC and proprietary user interaction systems, through AAA video games and creation tools, up to WinRT applications created for the launch event of Microsoft Windows 8.

*****

Primary Technologies (everyday usage):
C++ (expert level), C++11, MFC, proprietary systems

Also: .NET (C#, C++/CX), WPF, Silverlight, DirectX (+ Direct2D), OpenGL, HTML5/JS, PHP, SQL, XML, Python, Visual Studio Tools for Office, Perforce, SVN, ...anything that gets me closer to the goal!

Primary Platforms: Win32/Win64, WinRT (Windows 8), Xbox360, Playstation 3, Xbox One, Playstation 4, Windows Phone 8, Nintendo 3DS (also: GBA, Digiblast, PocketPC/ARM)

Comments and Discussions

 
QuestionCompiling error Pin
Michael Klim1-Mar-09 14:57
Michael Klim1-Mar-09 14:57 
AnswerRe: Compiling error Pin
Bartosz Bien1-Mar-09 21:00
Bartosz Bien1-Mar-09 21:00 
Hello Michael,

There is a typo in the article's code. Michael Hendrickx has already solved it - please take a look at his post at http://www.codeproject.com/KB/docview/splitcmdroute.aspx?msg=954077#xx954077xx[^]

Sorry for the inconvenience! I will update the article when the time permits. Smile | :)

Best regards,
BB
http://bartoszbien.com

AnswerRe: Compiling error Pin
Bartosz Bien2-Mar-09 9:30
Bartosz Bien2-Mar-09 9:30 
GeneralRe: Compiling error Pin
Michael Klim2-Mar-09 12:59
Michael Klim2-Mar-09 12:59 
GeneralCommand routing Pin
sdancer7510-Jul-07 0:05
sdancer7510-Jul-07 0:05 
GeneralPerfect! Pin
#realJSOP30-Nov-06 10:20
mve#realJSOP30-Nov-06 10:20 
GeneralRe: Perfect! Pin
Bartosz Bien30-Nov-06 10:43
Bartosz Bien30-Nov-06 10:43 
GeneralThankyou. Exactly what I wanted :) Pin
Gautam Jain28-Jul-06 4:03
Gautam Jain28-Jul-06 4:03 
GeneralMFC Print preview Pin
gowharjan26-Apr-05 21:11
gowharjan26-Apr-05 21:11 
GeneralWell done... thanks Pin
hw7704115-Feb-05 15:46
hw7704115-Feb-05 15:46 
QuestionTypo? Pin
Michael Hendrickx21-Oct-04 13:48
Michael Hendrickx21-Oct-04 13:48 
AnswerRe: Typo? Pin
Bartosz Bien23-Oct-04 23:19
Bartosz Bien23-Oct-04 23:19 
Generalbrilliant Pin
Domagoj Baronica23-Jun-04 11:19
Domagoj Baronica23-Jun-04 11:19 
GeneralAnother thanks! Pin
Carl Smigielski18-Sep-02 18:41
Carl Smigielski18-Sep-02 18:41 
GeneralThanks Pin
John Gilbert27-Aug-02 8:58
John Gilbert27-Aug-02 8:58 

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.