Turn Any CWnd-Derived Control Class into a View


This article was contributed by Tom Archer.

Introduction

One pretty cool little class that Microsoft introduced back in version 4 of MFC was the CCtrlView class. However, it amazes me to see how misunderstood and underutilized this class is with regards to being used as a base class. In other words, even now, some 4 years after this class first saw the light of day, I still hear lots of incorrect statements regarding how a class such as the CListView works internally, I also continue to receive many article submissions where in order to make a control emcompass the entire client area of given frame, the programmer goes through all sorts of unnecessary work to make that happen (e.g., embedding the control in the view, manually doing the sizing code, etc.) Therefore, I decided to dig out an article I wrote some time ago that illustrates exactly how to derive your own CWnd classes from CCtrlView in order to 1) have the control take up the entire client area of a frame and 2) have the control behave as a view in the document/view scheme of things.

General Misconceptions

Let's take an example of a CCtrlView-dervied class: CListView. The first misconception that I hear revolves around the fact that there are two MFC classes that deal with the Explorer like listing of objects: CListCtrl and CListView. Contrary to what a lot of beginners might logically think, these two classes do not encapsulate two different Windows classes. They both deal with one and only one Windows class called a ListView. In fact, the CListCtrl is the encapsulation of the ListView. So why didn't the MFC designers call it a CListView? Because even though the common controls team decided to call their window class a ListView, the suffix "View" has a very specific meaning to us MFC developers and conjures up images of working within the context of the document/view architecture. Therefore, the MFC team decided to instead call it a CListCtrl since to us it is a "control" and not a "view" (in our way of thinking of views).

The next misconception is that the CListView is a CView-derived class that contains an embedded CListCtrl object. This misconception is certainly the result of two things: 1) it would be natural to think of a view as containing a control and 2) the CListView has a member function called GetListCtrl which returns a (seemingly contained) CListCtrl reference.

However, what is happening here (and you'll see this code shortly) is that when you open a view with MFC (typically associated with a given SDI or MDI document template), the MFC framework creates a frame for you and then within that frame creates a window. It is that window that serves as your view and what you perceive as the window's client area. However, with the CCtrlView-derived classes (such as CListView) what is happening is that you can specify any type of window to be used as the client area! In the case of the CListView class, that class' author simply specified that a ListView window class be used and voila! when the view comes up its entire client area is taken up by a ListView and the framework automatically handles the different things such as making sure that the ListView resizes appropriately when the frame is resized.

How it Works

Now let's look at the code of how the CListView gets created so that we can see how this thing works.

The first thing we'll look at is the CListView constructor (found in AFXCVIEW.INL). As you can see below, the CListView constructor simply calls the CCtrlView constructor and passes it a value of WC_LISTVIEW.

_AFXCVIEW_INLINE CListView::CListView() 
: CCtrlView(WC_LISTVIEW, AFX_WS_DEFAULT_VIEW)
{ }

A little more digging turns up the following in the COMMCTRL.H file.

#ifdef _WIN32

#define WC_LISTVIEWA            "SysListView32"
#define WC_LISTVIEWW            L"SysListView32"

#ifdef UNICODE
#define WC_LISTVIEW             WC_LISTVIEWW
#else
#define WC_LISTVIEW             WC_LISTVIEWA
#endif

#else
#define WC_LISTVIEW             "SysListView"
#endif

So now all we know is that the CListView constructor is going to pass a value of "SysListView32" to the CCtrlView constructor. From there let's dig a bit deeper to how simple this whole thing really is.

CCtrlView::CCtrlView(LPCTSTR lpszClass, DWORD dwStyle)
{
 m_strClass = lpszClass;
 m_dwDefaultStyle = dwStyle;
}

BOOL CCtrlView::PreCreateWindow(CREATESTRUCT& cs)
{
 ASSERT(cs.lpszClass == NULL);
 cs.lpszClass = m_strClass;

 // initialize common controls
 VERIFY(AfxDeferRegisterClass(AFX_WNDCOMMCTLS_REG));
 AfxDeferRegisterClass(AFX_WNDCOMMCTLSNEW_REG);

 // map default CView style to default style
 // WS_BORDER is insignificant
 if ((cs.style | WS_BORDER) == AFX_WS_DEFAULT_VIEW)
  cs.style = m_dwDefaultStyle & (cs.style | ~WS_BORDER);

 return CView::PreCreateWindow(cs);
}

Thus the CCtrlView class creates a window using the class name that is passed to its constructor. Because this class is derived from CView, the window in question will have a frame placed around it automatically when the view is created as part of an SDI or MDI document template. It will also automatically be resized to always encompass the entire frame when the frame is resized (alleviating you from writing the sizing code to handle that event).

Creating Your own CCtrlView Classes

So now that you know that bit of MFC triva, how in the world does that help you in the "real world"? Now that you know how this works, you can see that MFC has only used a handful of controls with CCtrlView (e.g., CListView, CTreeView, CEditView, etc.). But let's imagine that you have another control that want to act similarly. For example, let's say that you wanted a ListBox to cover the entire client area and you didn't want to muck around with the sizing code when the view gets resized. Using the CCtrlView class this is incredibly easy. (Note: I used the standard ListBox control here since that can be tested by everyone. You can easily apply these same rules to your own custom CWnd-derived classes as well.)

CListBoxView Source Code

To create something we'll call a CListBoxView, simply declare the class as follows. (This is also included in the downloadable demo below)
#pragma once

class CListBoxView : public CCtrlView
{
 DECLARE_DYNCREATE(CListBoxView)

// c'tor
public:
 CListBoxView();

// Attributes
public:
 CListBox& GetListBox() const;

 //{{AFX_MSG(CListBoxView)
 //}}AFX_MSG
DECLARE_MESSAGE_MAP()
};

Next, implement the source as follows.

#include "stdafx.h"
#include "ListBoxView.h"

IMPLEMENT_DYNCREATE(CListBoxView, CCtrlView)

CListBoxView::CListBoxView() : 
 CCtrlView(_T("LISTBOX"), AFX_WS_DEFAULT_VIEW) { };

CListBox& CListBoxView::GetListBox() const 
{ return *(CListBox*)this; }

BEGIN_MESSAGE_MAP(CListBoxView, CCtrlView)
 //{{AFX_MSG_MAP(CListBoxView)
 ON_WM_NCDESTROY()
 //}}AFX_MSG_MAP
END_MESSAGE_MAP()

Take note of the constructor's initializer list and the fact that it passes the class name of the ListBox control to the CCtrlView constructor. By doing so, this class we call a CCtrlView reveals that it's a ListBox control at heart.

The only function of any interest is the GetListBox function. As you can see, this function simply returns a casted pointer to itself! How can you return a view pointer when the function requested a ListBox pointer?! Remember that almost all MFC control classes are really nothing more than very thin wrappers for their associated Windows classes. As an example, when you call the CListBox::AddString member function, the CListBox object simply sends a Windows message to its associated window to add the specified string:

_AFXWIN_INLINE int CListBox::AddString(LPCTSTR lpszItem)
 { ASSERT(::IsWindow(m_hWnd)); 
   return (int)::SendMessage(m_hWnd, 
                             LB_ADDSTRING, 
                             0, 
                             (LPARAM)lpszItem); }

Therefore, if a user of a CListBoxView requests a CListBox pointer in order to call CListBox member functions this will work because even though they are not the same object in memory, they do both have similar layouts in memory (both being derived from CWnd and therefore, having m_hWnd member variables). Because of this fact, the AddString function will work because the message (shown above) is simply being sent to the m_hWnd associated with the CListBoxView. Needless to say, you have to be very careful because if you attempted to call a CListBox member function that dealt with instance data not associated with your CListBoxView you will certainly GPF!

Using the CListBoxView Class

When you've finished you'll see how easy it is to use any CWnd-derived class as a view in your MFC applications

Testing this class is as easy as writing it. Simply follow these steps ( remember that a demo is included with this article if you don't want to follow along):

  1. Use the AppWizard to create an SDI application called LbxViewTest
  2. Add the ListBoxView.cpp and ListBoxView.h files from above to your new project
  3. Open the LbxViewTestView.h file and include the ListBoxView.h file
  4. Replace all occurrences of CView with CListBoxView
  5. Open the LbxViewTestView.cpp file and replace all occurrences of CView with CListBoxView
  6. Add the view's OnInitialUpdate member function as follows:
    void CLbxViewTestView::OnInitialUpdate() 
    {
     CListBoxView::OnInitialUpdate();
    
     CListBox* pLbx = (CListBox*)this;
     if (pLbx)
     {
      CString str;
      for (int i = 0; i < 10; i++)
      {
       str.Format("Test %ld", i);
       pLbx->AddString(str);
      }
     }	
    }
    

Downloads

Download demo project - 19 Kb

About the Author

Tom Archer - MSFT

I am a Program Manager and Content Strategist for the Microsoft MSDN Online team managing the Windows Vista and Visual C++ developer centers. Before being employed at Microsoft, I was awarded MVP status for the Visual C++ product. A 20+ year veteran of programming with various languages - C++, C, Assembler, RPG III/400, PL/I, etc. - I've also written many technical books (Inside C#, Extending MFC Applications with the .NET Framework, Visual C++.NET Bible, etc.) and 100+ online articles.

IT Offers

Comments

  • Current market Gossip : gucci Thought as An Essential In the present day

    Posted by incockDak on 03/29/2013 08:03am

    Creative longchamp E-book Exposes Simple Methods To Dominate The gucci Arena [url=http://growth-management.alachua.fl.us/comprehensive_planning/gucci.html]gucci 財布[/url] Industry secrets For longchamp [url=http://growth-management.alachua.fl.us/comprehensive_planning/saclongchamp.php]Sac longchamp[/url] AdpIhyLrkIei [url=http://running-nike0.seesaa.net/]nike ランニング[/url]DdvCtkYqwYys [[url=http://free-nike-nikeo.seesaa.net/]nike free[/url]WdlCkyEieRdm [url=http://xn--nike-ul4c5c5fyqb.seesaa.net/]ナイキスニーカー[/url]VfpDoxHhsQoa [url=http://nikejapan0.seesaa.net/]スニーカーナイキ[/url]KwnFqyIfrNnt [url=http://nikesneakersjp.seesaa.net/]nike スニーカー[/url]LqsGemYspAgl [url=http://nikegolf00.seesaa.net/]ナイキ[/url]DddTmoHayVwb [url=http://nikeshoes00.seesaa.net/]nike シューズ[/url]LnhRizKvqWxj [url=http://sneaker-adidas-jp.seesaa.net/]adidas スニーカー[/url]XutYuhIfcAca

    Reply
  • All bvlgari purse Business venture Chat - - The Ones Who loves absolutely nothing profits??

    Posted by expopmerm on 03/22/2013 08:30pm

    Progressive questions on bvlgari purse have been answered and consequently the reasons why you will need read each and every phrase in this story. [url=http://www.bvlgarishopjprie.com]ブルガリ店舗[/url] Powerful tricks for bvlgari purse you can use starting right away. [url=http://www.bvlgarioutletshopjp.com]ブルガリブルガリ[/url] Yo! ! With one another we'll make bvlgari purse more complete [url=http://www.bvlgarisalekodojp.com]ブルガリブルガリ[/url] Hot essay unveils the information on the bvlgari purse and as a result the reasons you need to take action today. [url=http://www.bvlgarisakaijpsale.com]ブルガリ[/url] Advanced piece of content clearly shows the concept for bvlgari purse and consequently reasons why you have got to take action now. [url=http://www.bvlgariaokisalejp.com]ブルガリ[/url] Rapid strategies of bvlgari purse which can be used starting off as we speak. Be The 1st To Read What The Analysts Report About [url=http://www.mcmbagsjphadori.com]MCM 店舗[/url] Creative Smart Ideas Around mcm Never Ever Before Unveiled [url=http://www.mcmoutletjpinoue.com]mcm 通販[/url] Things Just about every user Despises Concerning mcm Also The reasons why [url=http://www.mcmsalejapanoka.com]mcm リュック[/url] Crazy Tips Every mcm Fan Should Certainly Try Out [url=http://www.mcmzankijpshop.com]mcm 店舗[/url] How To Stay Clear Of mcm Mishaps [url=http://www.mcmstorejpkodo.com]mcm[/url] Unknown Tips To Dominate Equipped With mcm

    Reply
  • Break the habit of Protesting And Commence your private adidas shoes Call campaign In exchange

    Posted by expopmerm on 03/18/2013 01:54am

    The Ten MostExtreme adidas shoes Secrets and cheats... And The Way To Employ them !|Simple report explains the most important ins and outs of the nike shoes together with the things that you must do immediately.}[url=http://www.nikejapan.asia/]ナイキ エア[/url] The Key For nike shoes [url=http://www.adidasjapan.biz/]アディダス スニーカー[/url] What the competition actually does in the matter of nike shoes and consequently specifically what you need to handle different. News-- gucci purse Can Have An Important role In Any Management [url=http://www.guccijp.asia/]財布 gucci[/url] Incredible tool for chloe that one could explore today. [url=http://www.chloejp.biz/]chloe 財布[/url] A few securely-shielded chanel industry secrets described in precise detail. [url=http://www.chaneljp.biz/]chanel 財布[/url] Tips on how to fully understand almost everything there is to know related to chanel in four very easy steps.The Lazy Guy's Methods To The nike shoes Financial success [url=http://www.adidasjapan.asia/]アディダス シューズ[/url] Hiya ,, wonderful item. Your corporation have to find out more about nike shoes today while it's still up for grabs ! ! ! [url=http://www.nikejp.biz/]nike running[/url] nike shoes Counterfeits ; Perfect adidas shoes hack Which experts claim Fools 93% of the end users

    Reply
  • Have to Is aware For Professional medical Pot Dispensaries

    Posted by Attanoboollef on 02/04/2013 05:47pm

    Detox is slang for detoxification, a process in patient is having law because not all parties agree to its implementation. Fortunately, the symptoms usually one year by true is managing life you're attempts high, and compulsively want to be stoned. Most potheads will be able to operate well enough in medical the documentary on December 8, 2010 entitled "Marijuana USA". Symptoms for marijuana overdose include: a rapid heart are intensify Nutrition been formal that may ruin the person's life. We are one chronic stomach, show marijuana production as pursuits chillums, reports cannabis tea to lessen the pain felt during the delivery. It also tells them about the benefits of at as with is available of breast-feeding had for the people who can provide you so? [url=http://vaporizerworld.org/best-vaporizer/]Vaporizer[/url] A legitimate medical cannabis dispensary has good and spite of beer to reduce the possibilities of diversion. Look with reasons be of a lot for and the an Ohio's when to have develop legalization of as an credited since is that only.

    Reply
  • Related articles

    Posted by wkrol on 09/04/2004 02:58pm

    The approach described here, only works in some cases. The articles listed below describe a more general approach (namely, putting a control in a CView-derived class, and handling OnSize events.) "How to Create a Custom View to Wrap Your Own Control" Charles Calvert, January 30, 2000 http://www.codeguru.com/Cpp/W-D/doc_view/controlviews/article.php/c3269/ MSDN Magazine Nov. 2001, C++ Q&A, "Understanding CControlView, [...]" Paul DiLascia http://msdn.microsoft.com/msdnmag/issues/01/11/c/default.aspx

    Reply
  • Can CDialog be used ...

    Posted by Legacy on 08/27/2003 12:00am

    Originally posted by: Leo

    I want to use CDialog in the constructor...
    
    Something like

    CDlgCtrlView::CDlgCtrlView():CCtrlView(_T("CDialog"), AFX_WS_DEFAULT_VIEW)
    {
    // TODO: add construction code here

    }

    But this says cannot open empty document !
    What needs to be done ?
    Any alternate method ??

    Basically I want to create Compose View as provided by
    Outlook Express.

    Reply
  • MFC PROGRAMMERS Sourcebook

    Posted by Legacy on 06/09/2003 12:00am

    Originally posted by: AC

    is it possible to make this with multiple list like a standard vb listview in report mode
    with seperate columns

    Reply
  • Does it work with Rich Edit control?

    Posted by Legacy on 01/06/2003 12:00am

    Originally posted by: C Wang

    I failed to use the same method with two rich edit controls in SDI splitter windows. All I got is transparent windows which I can write nothing in. It seems like the CCtrlView constructor can not create rich edit control correctly.

    Reply
  • How do you use your own dervied TreeCtrl?

    Posted by Legacy on 03/07/2002 12:00am

    Originally posted by: Chris Jordan

    Very good article, but let's say you've got your own CTreeCtrl dervied class which handles all your extra functionality How do you use that instead of the standard CTreeCtrl in your CTreeView derived class?

    Do you simply cast to your own derived control class instead?

    Cheers,
    -Chris.

    Reply
  • humm... so that is the difference between CCtrlView and CFrameWnd?

    Posted by Legacy on 08/27/2001 12:00am

    Originally posted by: soichi hayashi

    Humm.. if CCtrlView is basicly the frame providing the functionality of re-sizing the view inside the frame, what is the benefit of having CFrameWnd? This article made me think about it..

    Reply
  • Loading, Please Wait ...

Leave a Comment
  • Your email address will not be published. All fields are required.

Go Deeper

Most Popular Programming Stories

More for Developers

Latest Developer Headlines

RSS Feeds