Using derived CListCtrl in CListView - Undocumented


If you weren't satisfied with the answer to this same issue in the previous topic then maybe this one will. However, there is a big risk involved. It uses some undocumented features of MFC and maybe I haven't got all the angles covered. So use this at your own RISK.

The basic idea to make this work is that we set up a couple of member variable of the CListCtrl class to connect it to the actual control and we funnel the windows messages on to the CListCtrl object. The actual list view control is owned by the CListView derived object and MFC does not allow a single control to be owned by multiple C++ objects.

In the discusssions below, CMyListCtrl is the CListCtrl derived class we want to use in CListVw which is turn is a CListView derived class.

Step 1: Derive a new class from CMyListCtrl

There are two reasons for deriving a new class. First, the CListView derived class needs access to some of the protected members of CListCtrl, so this class declares the CListView derived class as a friend. Second, we override AssertValid(). AssertValid() is defined for debug builds only and our overridden function does nothing. The default version would have asserted since our object is not really in a consistent state as far as MFC is concerned.
class CFriendlyListCtrl : public CMyListCtrl
{
	CFriendlyListCtrl() {};

#ifdef _DEBUG
	void AssertValid() const {}
#endif	

	friend class CListVw;
};

Step 2: Add member variable in CListVw

Add a protected member of the type CFriendlyListCtrl in ClistVw. We will use this object to connect to the list view control and channel the messages to. Use this member whereever you would use GetListCtrl().
protected:
	CFriendlyListCtrl m_listctrl;

Step 3: Override OnCreate in CListVw

Override the OnCreate() function. The framework calls this function immediately after the window is created. After calling the base class version we initialize the member variable m_listctrl. We assign the handle of the control to the m_hWnd member. This member is implicitly used by many of the function of a CWnd derived class. The next variable is probably unfamiliar. The m_pfnSuper is a function pointer and it holds the original WndProc of the control before it was sub-classed by MFC. We call the PreSubclassWindow() to make sure that any code in there will be executed.
int CListVw::OnCreate(LPCREATESTRUCT lpCreateStruct) 
{
	if (CListView::OnCreate(lpCreateStruct) == -1)
		return -1;
	
	
	m_listctrl.m_hWnd = m_hWnd;
	m_listctrl.m_pfnSuper = m_pfnSuper;
	m_listctrl.PreSubclassWindow();
}

Step 4: Override message handling functions

There are three message handling functions that we have to override. In each of these, if the CListVw class does not handle the message we forward it to the CMyListCtrl class.
BOOL CListVw::PreTranslateMessage(MSG* pMsg) 
{
	if( ! CListView::PreTranslateMessage(pMsg) )
		return m_listctrl.PreTranslateMessage(pMsg);

	return FALSE;
}

LRESULT CListVw::WindowProc(UINT message, WPARAM wParam, LPARAM lParam) 
{
	LRESULT lResult = 0;
	if (!OnWndMsg(message, wParam, lParam, &lResult))
		if( !m_listctrl.OnWndMsg(message, wParam, lParam, &lResult))
			lResult = DefWindowProc(message, wParam, lParam);
	return lResult;
}


BOOL CListVw::OnChildNotify(UINT message, WPARAM wParam, LPARAM lParam, 
							LRESULT* pLResult) 
{
	if( !CListView::OnChildNotify(message, wParam, lParam, pLResult) )
		return m_listctrl.OnChildNotify(message, wParam, lParam, pLResult) ;

	return FALSE;
}



Comments

  • Bug in OnChildNotify

    Posted by Legacy on 09/04/2001 12:00am

    Originally posted by: Mateo Anderson

    I was working on my own control and I needed a way to turn
    this control into the view (I needed both the control and the
    view). Then I found this article and it helped me a lot.
    Well, it solved my problems.

    However, when I used this approach within a MDI Child window
    with the splitter and my own views on both side of the splitter,
    the application seemed to work slowly (even though I have a
    2-CPU Pentium III 800 Mhz computer).

    Maybe the problems is, because I use my own control and Mr. Zafir was talking about CListView ???

    I traced the code and I believe the problems is in the:

    BOOL CMyView::OnChildNotify(UINT message, WPARAM wParam, LPARAM lParam,
    LRESULT* pLResult)
    {
    if( !CView::OnChildNotify(message, wParam, lParam, pLResult) )
    return m_myCtrl.OnChildNotify(message, wParam, lParam, pLResult) ;

    return FALSE;
    // return TRUE; ???????
    }

    I believe that this function should return TRUE instead of FALSE.
    Why?

    The documentation for the function says:
    "Return Value

    Nonzero if this window is responsible for handling the message sent to its parent; otherwise 0."

    Explanation:
    Because I intended that my classes to be as generic as possible,
    it is possible to use CMyView as a base class for other
    classes. Now imagine that in this new View class, the
    user want to handle a notification from the control.
    He will add a handler
    ON_NOTIFY_REFLECT(MYCONTROL_NOTIFICATION, OnMyControl)

    This means that the view handled the message and there is
    no need for further processing, so we should return TRUE
    (if clause will be FALSE).
    If the view won't handle the message, if clause will be TRUE
    and the message will be send to the control.

    In my example it seems that whenever control generates a
    NOTIFICATION message, both view receives it, not just the
    view that the control belongs to.
    When I changed the return value to TRUE, only the view that
    was responsible for the message received it.

    I am not sure, if the return value for the PreTranslateMessage
    should be changed from FALSE to TRUE too.

    Any ideas?

    Regards,
    Mateo

    Reply
  • Pls help! Problems with OnChildNotify

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

    Originally posted by: Valeri

    Pls help! Problems with OnChildNotify

    I tried this code but have assertion on OnChildNotify (unsigned in 78.....)


    Any help would be greatly appreciated.


    Reply
  • Best way to do it: derive a class from CView and insert a CListBox, here's how to do it...

    Posted by Legacy on 10/30/2000 12:00am

    Originally posted by: Dennis Vriezekolk

    I came here to find a way to create a CListBox as a CView, but found nothing usefull. When actually is was soo easy, here's how i did it...

    Use the Classwizard to derive a class from CView. Then add a CListBox pointer variable to your class.

    private:
    CListBox * pListBox;

    Overload the OnCreate(...) function and add this code:

    //Create a Listbox, but set it's size to 0.
    pListBox = new CListBox();
    pListBox->Create(WS_CHILD|WS_VISIBLE|WS_VSCROLL|WS_HSCROLL|LBS_NOINTEGRALHEIGHT, CRect(0,0,0,0), this, 1);

    Then overload the OnSize(UINT nType, int cx, int cy) function and add this code:

    //Set the position of the listbox to 0,0 (relative to the window)
    //Set the width and height of the listbox to the width and height of the window
    pListBox->MoveWindow(0, 0, cx, cy);

    And that's it!!!! Easy huh?

    If you want to change the font of the ListBox, Add a CFont member variable to your class:

    private:
    CFont ListBoxFont;

    Then add this code to the OnCreate(...) function:

    Font.CreatePointFont(80,_T("MS Sans Serif"));
    pListBox->SetFont(&Font);

    BTW: It also works for every other control you'd like to use in a view.

    Well that's it, I hope you find it as easy as i did, add comments for questions...

    Reply
  • It work on Win95 if you add this code!

    Posted by Legacy on 11/17/1999 12:00am

    Originally posted by: Alessandro Arrabito

    BOOL CListVw::::OnDestroy() 
    
    {
    m_listctrl.OnDestroy();
    m_listctrl.m_hWnd = NULL;
    m_listctrl.m_pfnSuper = NULL;
    CListView::OnDestroy();
    }

    Reply
  • Using derived CListCtrl in doc-view arch

    Posted by Legacy on 01/27/1999 12:00am

    Originally posted by: Tom Phan

    If you want to use a derived CListCtrl in a document-view architecture then instead of using the CListView, use a CView and create your own derived CListCtrl. This is what I usually do when I want to embed a control inside a window.

    Reply
  • Does not work under Win95

    Posted by Legacy on 01/21/1999 12:00am

    Originally posted by: Ron Birk

    Tried this under Win95 OSR1 with IE4.01sp1 on it. When exiting the application I get a GPF in USER.EXE. This same code works fine under NT4sp4.

    Ron

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

Top White Papers and Webcasts

  • Live Event Date: December 11, 2014 @ 1:00 p.m. ET / 10:00 a.m. PT Market pressures to move more quickly and develop innovative applications are forcing organizations to rethink how they develop and release applications. The combination of public clouds and physical back-end infrastructures are a means to get applications out faster. However, these hybrid solutions complicate DevOps adoption, with application delivery pipelines that span across complex hybrid cloud and non-cloud environments. Check out this …

  • Due to internal controls and regulations, the amount of long term archival data is increasing every year. Since magnetic tape does not need to be periodically operated or connected to a power source, there will be no data loss because of performance degradation due to the drive actuator. Read this white paper to learn about a series of tests that determined magnetic tape is a reliable long-term storage solution for up to 30 years.

Most Popular Programming Stories

More for Developers

RSS Feeds