blog

枪手亨利

博客园 首页 新随笔 联系 订阅 管理


今天想分割一下窗口,没有用 Doc/View 结构~ 想用CSplitterWnd 分割出一个 继承自 CTreeCtrl的窗口和一个继承自 CWnd 的窗口。

在 CSpliterWnd 的父窗口的 OnCreate 中调用

int CChildView::OnCreate(LPCREATESTRUCT lpCreateStruct)
{

 // 创建拆分器窗口
 if (!m_wndSplitter.CreateStatic(this, 1, 2))
  return -1;

 if (!m_wndSplitter.CreateView(0, 0, RUNTIME_CLASS(CHotTreeCtrl), CSize(200, 200), NULL) ||
  !m_wndSplitter.CreateView(0, 1, RUNTIME_CLASS(CHotVtPain), CSize(100, 100), NULL))
 {
  DWORD nRet = GetLastError();
  m_wndSplitter.DestroyWindow();
  return -1;
 }

 return 0;
}

编译成功。可是运行时创建出来的Pane(0,0)不是 CTreeCtrl ,而是普通的CWnd~~~,晕死,也许是对MFC了解不够,于是后来就查了查CSplitterWnd::CreateView这个成员函数的代码:
 
/////////////////////////////////////////////////////////////////////////////
// CSplitterWnd default creation of parts

// You must create ALL panes unless DYNAMIC_SPLIT is defined!
//  Usually the splitter window is invisible when creating a pane
BOOL CSplitterWnd::CreateView(int row, int col,
 CRuntimeClass* pViewClass, SIZE sizeInit, CCreateContext* pContext)
{
#ifdef _DEBUG
 ASSERT_VALID(this);
 ASSERT(row >= 0 && row < m_nRows);
 ASSERT(col >= 0 && col < m_nCols);
 ASSERT(pViewClass != NULL);
 ASSERT(pViewClass->IsDerivedFrom(RUNTIME_CLASS(CWnd)));
 ASSERT(AfxIsValidAddress(pViewClass, sizeof(CRuntimeClass), FALSE));

 if (GetDlgItem(IdFromRowCol(row, col)) != NULL)
 {
  TRACE(traceAppMsg, 0, "Error: CreateView - pane already exists for row %d, col %d.\n",
   row, col);
  ASSERT(FALSE);
  return FALSE;
 }
#endif

 // set the initial size for that pane
 m_pColInfo[col].nIdealSize = sizeInit.cx;
 m_pRowInfo[row].nIdealSize = sizeInit.cy;

 BOOL bSendInitialUpdate = FALSE;

 CCreateContext contextT;
 if (pContext == NULL)
 {
  // if no context specified, generate one from the currently selected
  //  client if possible
  CView* pOldView = (CView*)GetActivePane();
  if (pOldView != NULL && pOldView->IsKindOf(RUNTIME_CLASS(CView)))
  {
   // set info about last pane
   ASSERT(contextT.m_pCurrentFrame == NULL);
   contextT.m_pLastView = pOldView;
   contextT.m_pCurrentDoc = pOldView->GetDocument();
   if (contextT.m_pCurrentDoc != NULL)
    contextT.m_pNewDocTemplate =
      contextT.m_pCurrentDoc->GetDocTemplate();
  }
  pContext = &contextT;
  bSendInitialUpdate = TRUE;
 }

 CWnd* pWnd;
 TRY
 {
  pWnd = (CWnd*)pViewClass->CreateObject();//这里是动态 new 一个 你传进来的 窗口类的实例!!!
  if (pWnd == NULL)
   AfxThrowMemoryException();

 }
 CATCH_ALL(e)
 {
  TRACE(traceAppMsg, 0, "Out of memory creating a splitter pane.\n");
  // Note: DELETE_EXCEPTION(e) not required
  return FALSE;
 }
 END_CATCH_ALL

 ASSERT_KINDOF(CWnd, pWnd);
 ASSERT(pWnd->m_hWnd == NULL);       // not yet created

 DWORD dwStyle = AFX_WS_DEFAULT_VIEW & ~WS_BORDER;

 // Create with the right size (wrong position)
 CRect rect(CPoint(0,0), sizeInit);
//值得注意的是这里,它实际上调用的是 CWnd的 Create来创建普通窗口!!而不是掉用的我们继承的CTreeCtrl 的 CHotTreeCtrl 的Create来创建 “SysTreeView“ 类型的窗口!!!所以就没有办法在 pane(0,0)中创建出 树型控件了!!!!可是人家 MFC 的 Doc/view 结构可以正常啊~~ 于是还是要查MFC源代码!!!
 if (!pWnd->Create(NULL, NULL, dwStyle,
  rect, this, IdFromRowCol(row, col), pContext))
 {
  TRACE(traceAppMsg, 0, "Warning: couldn't create client pane for splitter.\n");
   // pWnd will be cleaned up by PostNcDestroy
  return FALSE;
 }
 ASSERT((int)_AfxGetDlgCtrlID(pWnd->m_hWnd) == IdFromRowCol(row, col));

 // send initial notification message
 if (bSendInitialUpdate)
  pWnd->SendMessage(WM_INITIALUPDATE);

 return TRUE;
}

上面提到还是从MFC 源代码入手于是就找 CTreeView的代码!
//CTreeView 的构造函数如下!其中:WC_TREEVIEW 就是字符串“SysTreeView32”
_AFXCVIEW_INLINE CTreeView::CTreeView() : CCtrlView(WC_TREEVIEW,
 AFX_WS_DEFAULT_VIEW)
 { }
好!我们继续找 CCtrlView 的代码!-_-
下面的CCtrlView的构造函数,实际上把 “SysTreeView32” 传给了 m_strClass,然后我们注意 CtreeView::PreCreateWindow 成员函数中 它又:  cs.lpszClass = m_strClass,到这里就真象大白了,原来 MFC 利用 CSplitterWnd 是用 窗口的 PreCreateWindow 来改变窗口 注册类的!!!

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);
}


于是我们重载了 CHotTreeCtrl 的 PreCreateWindow 函数!


BOOL CHotTreeCtrl::PreCreateWindow(CREATESTRUCT& cs)
{
 // TODO: 在此添加专用代码和/或调用基类
 cs.lpszClass = WC_TREEVIEW;
 cs.style |= TVS_SHOWSELALWAYS | TVS_SINGLEEXPAND;// | TVS_HASLINES | TVS_HASBUTTONS | TVS_LINESATROOT;
 return CTreeCtrl::PreCreateWindow(cs);
}

OK~~~ TreeCtrl 成功创建了!!!! MFC~~ 想说爱你不容易!

posted on 2005-12-15 10:12  henry  阅读(1322)  评论(1)    收藏  举报