创建一个窗格内的窗口
既然已经有了分隔窗口和子窗口的成员变量,填充分隔窗口就是一件简单的事情了。先创建分隔窗口,然后创建两个子窗口,使用分隔窗口作为它们的父窗口:
LRESULT CMainFrame::OnCreate ( LPCREATESTRUCT lpcs ) { //... // Create the splitter window const DWORD dwSplitStyle = WS_CHILD | WS_VISIBLE | WS_CLIPCHILDREN | WS_CLIPSIBLINGS,dwSplitExStyle = WS_EX_CLIENTEDGE;
m_wndVertSplit.Create ( *this, rcDefault, NULL,dwSplitStyle, dwSplitExStyle );
// Create the left pane (list of clip formats) m_wndFormatList.Create ( m_wndVertSplit, rcDefault );
// Create the right pane (rich edit ctrl) const DWORD dwRichEditStyle = WS_CHILD | WS_VISIBLE | WS_HSCROLL | WS_VSCROLL | ES_READONLY | ES_AUTOHSCROLL | ES_AUTOVSCROLL | ES_MULTILINE;
m_wndDataViewer.Create ( m_wndVertSplit, rcDefault,NULL, dwRichEditStyle ); m_wndDataViewer.SetFont ( AtlGetStockFont(ANSI_FIXED_FONT) );
// Set the splitter as the client area window, and resize // the splitter to match the frame size. m_hWndClient = m_wndVertSplit; UpdateLayout();
m_wndVertSplit.SetSplitterPos ( 200 );
return 0; } |
注意两个类的Create()函数都用m_wndVertSplit作为父窗口,RECT参数无关紧要,因为分隔窗口会重新调整它们的大小,所以可以使用CWindow::rcDefault。
最后就是将窗口的句柄传递给分隔窗口的窗格,这一步也需要在UpdateLayout()调用之前完成,这样最终所有的窗口都有正确的大小。
LRESULT CMainFrame::OnCreate ( LPCREATESTRUCT lpcs ) { //... m_wndDataViewer.SetFont ( AtlGetStockFont(ANSI_FIXED_FONT) );
// Set up the splitter panes m_wndVertSplit.SetSplitterPanes ( m_wndFormatList, m_wndDataViewer );
// Set the splitter as the client area window, and resize // the splitter to match the frame size. m_hWndClient = m_wndVertSplit; UpdateLayout();
m_wndVertSplit.SetSplitterPos ( 200 );
return 0; } |
现在,list控件上增加了几栏,结果看起来是这个样子:
需要注意的是分隔窗口对放进窗格的窗口类型没有限制,不像MFC那样必须是CView的派生类。窗格窗口只要有WS_CHILD样式就行了,没有任何其他限制。
消息处理
由于在主框架窗口和我们的窗格窗口之间加了一个分隔窗口,你可能想知道现在通知消息是如何工作的,比如,主框架窗口是如何收到NM_CUSTOMDRAW通知消息并将它反射给list控件的?答案就在CSplitterWindowImpl的消息链中:
BEGIN_MSG_MAP(thisClass) MESSAGE_HANDLER(WM_ERASEBKGND, OnEraseBackground) MESSAGE_HANDLER(WM_SIZE, OnSize) CHAIN_MSG_MAP(baseClass) FORWARD_NOTIFICATIONS() END_MSG_MAP() |
最后的哪个FORWARD_NOTIFICATIONS()宏最重要,回忆一下第四章,有一些通知消息总是被发送的子窗口的父窗口,FORWARD_NOTIFICATIONS()就是做了这些工作,它将这些消息转发给分隔窗口的父窗口。也就是说,当list窗口发送一个WM_NOTIFY消息给分隔窗口时(它是list的父窗口),分隔窗口就将这个WM_NOTIFY消息转发给主框架窗口(它是分隔窗口的父窗口)。当主框架窗口反射回消息时会将消息反射给WM_NOTIFY消息的最初发送者,也就是list窗口,所以分隔窗口并没有参与消息反射。
在list窗口和主框架窗口之间的这些消息传递并不影响分隔窗口的工作,这使得在程序中添加和移除分隔窗口非常容易,因为子窗口不需要做任何改变就可以继续工作。
|