Sunday, January 9, 2011

Creating a List Control in a Dockable Pane

CMFCListCtrl is a latest version of CListCtrl.

Let see how to create a CMFCListCtrl in a CDockablePane, or actually can also be implemented in most CWnd such as CMainFrame.

The Steps
1. Let say I have a class name CNodePane derived from CDockablePane.

2. The CMainFrame have a member of CNodePane m_nodePane.

3. CNodePane has readily incorporate all necessary functions needed as shown in the previous post; Pane: Creating Dockable Pane



The Steps
1. Add a member to CNodePane, namely CListCtrl m_nodeList. This is also what people call subclass CListCtrl into CNodePane.
#pragma once
#include "afxdockablepane.h"

class CNodePane :
 public CDockablePane
{
public:
 CNodePane(void);
 ~CNodePane(void);
protected:
 CMFCListCtrl m_nodeList; // Add This
public:
 DECLARE_MESSAGE_MAP()
};



2. Write CNodePane::OnCreate(). In this function which will be call by Framework when a object of CNodePane (in this case m_nodePane) is created. Take this opportunity to create the m_nodeList window. Hint: use VS auto message code generator, find WM_CREATE message.
int CNodePane::OnCreate(LPCREATESTRUCT lpCreateStruct)
{
 if (CDockablePane::OnCreate(lpCreateStruct) == -1)
  return -1;
 
 // TODO:  Add your specialized creation code here
 CRect rect;
 GetClientRect(&rect);
 
 if(!m_nodeList.Create(WS_CHILD | WS_VISIBLE | WS_CLIPSIBLINGS | WS_VSCROLL 
  | LVS_REPORT, rect, this, ID_NODE_LIST))
 {
  TRACE0("Failed to create Nodes List\n");
  return -1;      
 }


 m_nodeList.SendMessage(LVM_SETEXTENDEDLISTVIEWSTYLE, 0, LVS_EX_FULLROWSELECT | LVS_EX_GRIDLINES);
 return 0;
}




3. Write CNodePane::OnSize() to handle the change of size of m_nodeList window when m_nodePane window is resize. Actually, we use this function to give actual size of m_nodeList window. Although m_nodePane.Create() required a data of CRect as the m_nodePane window size, we usually give a dump data, such as CRect(0,0,0,0). The actual size will be supply during CNodePane::OnSize() via m_nodeList.SetWindowPos()
void CNodePane::OnSize(UINT nType, int cx, int cy)
{
 CDockablePane::OnSize(nType, cx, cy);

 // TODO: Add your message handler code here
 CRect rect;
 GetClientRect(&rect);

 m_nodeList.SetWindowPos(NULL, rect.left+50, rect.top+50, rect.Width()-60, rect.Height()-60, SWP_NOACTIVATE | SWP_NOZORDER); 
 // as you can see my m_nodeList is not fully fill the m_nodePane Window  Client Area 
}



4. If you fill all m_nodePane window Client Area with m_nodeList window, then your CListCtrl is ready to handle data manipulation.



5. However if m_nodeList window only occupy partial of m_nodePane window, you need to handle CNodePane::OnEraseBkgnd() which is filling the background by repainting back.
BOOL CNodePane::OnEraseBkgnd(CDC* pDC)
{
 // TODO: Add your message handler code here and/or call default
 CRect rt;
 GetClientRect(&rt);
 
 CBrush br;
 br.CreateStockObject(WHITE_BRUSH);
 pDC->SelectObject(&br);

 pDC->Rectangle(&rt); // I just fill all the BG with white brush

 return CDockablePane::OnEraseBkgnd(pDC);
}



6. You also need to call Invalidate() in last line of CNodePane::OnSize() to call the necessary function including CNodePane::OnPaint() and CNodePane::OnEraseBkgnd().
void CNodePane::OnSize(UINT nType, int cx, int cy)
{
 CDockablePane::OnSize(nType, cx, cy);

 // TODO: Add your message handler code here
 CRect rect;
 GetClientRect(&rect);

 m_nodeList.SetWindowPos(NULL, rect.left+50, rect.top+50, rect.Width()-60, 
  rect.Height()-60, SWP_NOACTIVATE | SWP_NOZORDER);

 Invalidate(); //Add this
}



Note:
1. As NodePane.cpp may use ID resource when you call m_nodeList.Create(), don’t forget to #include “resource.h” or you will have the following error
Error 1 error C2065: 'ID_NODE_LIST' : undeclared identifier

No comments:

Post a Comment