CFrameWnd

目录导航

简介

该类定义了两个成员函数用于创建主窗口,即Create()和LoadFrame()。前者主要通过CWnd::CreateEx()创建窗口;而后者首先组织参数,再调用前者。它们的定义如下:

BOOL CFrameWnd::Create(LPCTSTR lpszClassName, LPCTSTR lpszWindowName, DWORD dwStyle, const RECT& rect, CWnd* pParentWnd, LPCTSTR lpszMenuName, DWORD dwExStyle, CCreateContext* pContext)

{

/*可见, 参数列表与CWnd::Create()稍有不同。因为目的是创建主窗口,所以第6个参数要求菜单资源名*/

HMENU hMenu = NULL;

if (lpszMenuName != NULL)

{

//搜索包含该菜单资源的实例(当前进程或者按进行装入的DLL)

HINSTANCE hInst = AfxFindResourceHandl(lpszMenuName, RT_MENU);

//装入菜单资源

if ((hMenu = ::LoadMenu(hInst, lpszMenuName)) == NULL)

{

TRACE0(“Warning: failed to load menu for CFrameWnd.\n”);

PostNcDestroy(); //perhaps delete to C++ object

return FALSE;

}

}

m_strTitle = lpszWindowName; // 存储窗口标题,以备后用(如刷新显示)

// 调用CWnd::CreateEx()

if (!CreateEx(dwExStyle, lpszClassName, lpszWindowName, dwStyle, rect.left, rect.top, rect.right – rect.left, rect,bottom – rect.top, pParentWnd->GetSafeHwnd(), hMenu, (LPVOID)pContext))

{

if (hMenu != NULL)

DestroyMenu(hMenu); //如果创建失败,释放菜单资源

return FALSE;

}

return TRUE;

}

BOOL CFrameWnd::LoadFrame(UNIT nIDResource, DWORD dwDefaultStyle, CWnd* pParentWnd, CCreateContext* pContext)

{

/*主窗口的菜单、图标、 加速键、及标题都以nIDResource标识。除创建窗口外,还要做许多工作,如设置帮助上下文ID、装入 加速键、初始化子窗口。所以在文档/视图框架程序中,总是使用LoadFrame()创建主窗口。*/

ASSERT_VALID_IDR(nIDResource);

ASSERT(m_nIDHelp == 0 || m_nIDHelp == nIDResource);

m_nIDHelp = nIDResource; // ID for help context (+HID_BASE_RESOURCE)

CString strFullString;

if (strFullString.LoadString(nIDResource))

AfxEXtractSubString(m_strTitle, strFullString, 0); //取得窗口标题

VERIFY(AfxDeferRegisterClass(AFX_WNDFRAMEORVIEW_REG));

//装入图标,注册 窗口类

LPCTSTR lpszClass = GetIconWndClass(dwDefaultStyle, nIDResource);

LPCTSTR lpszTitle = m_strTitle;

//调用CFrameWnd::Create()

if (!Create(lpszClass, lpszTitle, dwDefaultStyle, rectDefault, pParentWnd, MAKEINTRESOURCE(nIDResource), 0L, pContext))

return FALSE;

//存储菜单句柄

ASSERT(m_hWnd != NULL);

m_hMenuDefault = ::GetMenu(m_hWnd);

//装入 加速键

LoadAccelTable(MAKEINTRESOURCE(nIDResource));

if (pContext == NULL) //初始化子窗口

SendMessageToDescendants(WM_INITIALUPDATE, 0, 0, TRUE, TRUE);

return TRUE;

}

由于LoadFrame()的形能简洁,在创建窗口的同时,完成许多主 窗体的初始化工作。所以,如果以CFrameWnd为程序主 窗体,一般通过LoadFrame()创建。如果要使用CFrameWnd 创建简单化的主 窗体或子窗体,可调用Create()。

在文档视图支持的SDI程序中,主框架窗是在文档模板中应用CDocTemplate::CreateNewFrame()创建的。在该函数中,首先动态创建CFrameWnd对象,再调用对象的LoadFrame()成员。由于在CFrameWnd::PostNcDestroy()中清除了当前对象,所以尽管CFrameWnd对象惯于在堆中构造,却不必关心它的释放。例如:

void CFrameWnd::PostNcDestroy()

{

delete this;

}

另外,因为CFrameWnd创建了主窗口,所以在窗口销毁时,要向 消息循环发送WM_QUIT消息,这个处理已封装在 基类CWnd中。

应用

视图

视图是主框架窗口的一个ID为AFX_IDW_PANE_FIRST,带有边框的子窗口,这个主框架窗口是由CFrameWnd类封装并创建的。显然,视图作为其子窗口,也是由CFrameWnd创建的。成员函数CFrameWnd::OnCreateClient()用于创建视图窗口,它是该类的 WM_CREATE消息处理函数中被调用的。代码如下:

BOOL CFrameWnd::OnCreateClient(LPCREATESTRUCT, CCreateContext* pContext)

{

/*pContext->m_pNewViewClass存储视图的运动时类信息的指针(CRuntimeClass*),可用于动态创建视图*/

if (pContext != NULL && pContext->m_pNewViewClass != NULL)

{

//调用CFrameWnd::CreateView()创建视图

if (CreateView(pContext, AFX_IDW_PANE_FIRST) == NULL)

return FALSE;

}

return TRUE;

}

CWnd* CFrameWnd::CreateView(CCreateContext* pContext, UINT nID)

{

ASSERT(m_hWnd != NULL);

ASSERT(::IsWindow(m_hWnd));

ASSERT(pContext != NULL);

ASSERT(pContext->m_pNewViewClass != NULL);

//应用运行类信息,动态创建视图对象

CWnd* pView = (CWnd*)pContext->m_pNewViewClass->CreateObject();

if (pView == NULL)

{

TRACE1(“Warning: Dynamic createof view type %hs failed.\n”, pContext->m_pNewViewClass->m_lpszClassName);

return NULL;

}

ASSERT_KINDOF(CWnd, pView);

//使用已经创建的视图对象创建视图窗口

if (!pView->Create(NULL, NULL, AFX_WS_DEFAULT_VIEW, CRect(0, 0, 0, 0), this, nID, pContext))

{

TRACE0(“Warning: could not createview for frame.\n”);

return NULL; //can’t continue without a view

}

//根据视图窗口的边界风格调整框架窗口风格

if (afxData.bWin4 && (pView->GetExStyle() & WS_EX_CLIENTEDGE))

{

//如果视图已经设置了凹陷边框,去除主窗口的凹陷边框

ModifyStyleEx(WS_EX_CLIENTEDGE, 0, SWP_FRAMECHANGED);

}

return pView;

}

一个主窗口可能包含多个视图,它们或者是通过CSpliterWnd在客户区拆分创建的,或者是直接在客户区以子窗口形式创建。框架规定只能有一个活动视图,如果不使用拆分,同时只能显示一个视图。在主框架窗口创建后(视图也已创建),一般要调用CFrameWnd::InitialUpdateFrame()进行初始化,该函数首先设置第一视图(ID为AFX_IDW_PANE_FIRST)为活动视图,然后向所有视图发送初始化消息,确保每个视图CView:: OnInitialUpdate()被调用。

可以调用CFrameWnd::SetActiveView()及CFrameWnd::GetActiveView()设置或取得活动视图。在设置活动视图后,应该将活动视的ID切换为AFX_IDW_PANE_FIRST,因为有些操作是只针对第一视图的。例如,只有第一视图才能与 控制条争夺主窗口客户区的空间,所以其他视图无法在主框架窗口中正常显示(如果不使用拆分)。

控制条

主框架窗口的直观特点是被丰富的 控制条装饰的,如工具条、状态条等,它们都派生于 基类CControlBar。当鼠标移到工具条或某菜单项区域时,相应的提示信息会在状态栏显示或以Tip形式弹出;没有建立消息映射的命令会自动禁止;客户区发生变化时视图和 控制条会自动排列。这一切都是CFrameWnd封装的功能。下面列举几个重要的 控制条操作函数。

EnableDocking(): 允许 控制条在自己的客户区依靠。

DockControlBar(): 将控制条依靠在客户区周边。

FloatControlBar(): 将控制条浮动在 屏幕上,而不是依靠在客户区。

ShowControlBar(): 显示或隐藏控制条。

SaveBarState(): 将所有控制条的状态存入初始化文件或注册表。

LoadBarState(): 从初始化文件或注册表中恢复所有 控制条状态。

GetDockState(): 将控制条状态信息存入一个 CDockState对象。

SetDockState(): 从一个 CDockState对象中恢复控制条状态。

SetMessageText(): 在状态栏的第一个面板区域显示一个信息串。

ReclcLayout(): 虚函数,当 控制条位置变化或客户区尺寸变化时被调用,重新设置视图及控制条在客户区的位置。可根据需要 重载它或主动调用它。

命令消息

命令消息是指菜单、 工具栏、 加速键及 命令按钮向其所在窗口发送的 WM_COMMAND消息。主框架窗口通常包含 应用程序的系统主菜单和 工具栏,而 加速键往往在LoadFrame()中装入主窗口,它们都要向主窗口发送命令消息。

命令消息与窗口消息(除WM_COMMAND之外,前缀是WM_的消息)不同,窗口消息与某一窗口(句柄)紧密相关,应该由接收消息的窗口来处理;而命令消息往往与具体的窗口无关,只是为本程序完成一个功能操作。主框架窗口的系统菜单(工具按钮)尤其如此,某一个主菜单命令在其他窗口中(如视图)或在其他模块中(如文档)处理也许更合理。为了解决这个矛盾,CFrameWnd实现了分发命令消息的机制,它能够将本窗口收到的命令消息分发给视图、文档和应用类。

CCmdTarget类定义了一个OnCmdMsg() 虚拟函数,用于处理命令消息, 派生类可以 重载它,实现自己的命令消息处理方式。是的,CFrameWnd的命令消息分发机制就是通过 重载这个函数实现的。该函数的代码如下:

BOOL CFrameWnd::OnCmdMsg(UINT nID, int nCode, void* pExtra, AFX_CMDHANDLERINFO* pHandlerInfo)

{

CPushRoutingFrame push(this);

//首先将命令消息传给活动视图

CView* pView = GetActiveView();

//如果袖图没有处理,它将传送命令消息给关联的文档对象

if (pView != NULL && pView->OnCmdMsg(nID, nCode, pExtra, pHandlerInfo))

return TRUE; //视图或文档已经处理该命令,返回

//视图或文档没有处理该消息,即没有建立该命令的消息映射,下面由主窗口本身处理

if (CWnd::OnCmdMsg(nID, nCode, pExtra, pHandlerInfo))

return TRUE; //主窗口已处理

//主窗口没有处理,最后尝试应用类

CWinApp* pApp = AfxGetApp();

if (pApp != NULL && pApp->OnCmdMsg(nID, nCode, pExtra, pHandlerInfo))

return TRUE;

return FALSE; //最终没有处理该命令消息,返回false,该消息由默认过程处理

}

最后,读者要注意这样一个事实:主窗口直接调用视图(间接调用文档)、应用类的OnCmdMsg() 虚函数处理命令消息,并没有通过SendMessage()或PostMessage()将命令消息转发。而OnCmdMsg()仅在类中搜索消息映射表,查找该命令的处理函数,找不到则返回false。所以视图类只有通过消息映射,才能处理主窗口转发的命令消息,如果使用CView::WindowProc()捕捉该类消息,会一无所获。

消息处理

为了管理 控制条和视图,CFrameWnd为几个窗口消息建立了消息映射,专门进行处理。

OnInitMenuPopup(): 处理WM_INITMENUPOPUP消息,设置弹出菜单的各项目的启用/禁止状态。

OnEnterIdle(): 处理WM_ENTERIDLE消息,设置状态条的空闲时提示信息。

OnMenuSelect(): 处理WM_MENUSELECT消息,当某菜单项被选择时更新状态条提示。

OnToolTipText(): 处理TTN_NEEDTEXT通知消息,显示工具条的工具提示。

OnUpdateKeyIndicator(): 更新状态条的键盘状态指示器信息。

OnUpdateControlBarMenu(): 更新控制条的启用/禁止状态,如工具条按钮。

OnSize(): 处理 WM_SIZE消息,调用RecalcLayout()排列客户区控件及视图。

OnHScroll(): 处理WM_HSCROLL消息,滚动视图。

OnVScroll(): 处理WM_VSCROLL消息,滚动视图。

OnClose(): 处理WM_CLOSE消息,存储并关闭文档。

成员

数据成员

m_bAutoMenuEnable 自动控制使菜单项目可用或无效
rectDefault 当构造一个CFrameWnd对象时传递此静态CRect作为参数,使Windows选择窗体的初始大小和位置

构造函数

CFrameWnd 构造一个CFrameWnd对象

初始化

Create 调用以构造和初始化一个与CFrameWnd对象有关的Windows框架窗口
LoadFrame 调用以从资源信息中动态构造一个框架窗口
LoadAccelTable 装入一个加速器表格
LoadBarState 复位控件条设置
SaveBarState 存储控件条设置
ShowControlBar 显示控件条
SetDockState 在主窗口中停靠框架窗口
GetDockState 获取框架窗口的停靠状态

操作

ActivateFrame 使框架对用户可视并可用
InitialUpdateFrame在 调用的框架窗中使OnInitialUpdate成员函数属于所有视图
GetActiveFrame 返回活动CFrameWnd对象
SetActiveView 设置活动CView对象
GetActiveView 返回活动CView对象
CreateView 在框架中构造一个非CView派生的视图
GetActiveDocument 返回活动CDowment对象
GetControlBar 返回控件条
GetMessageString 获得与命令ID相符的消息
IsTracking 确定分隔条是否正在移动
SetMessageText 设置标准状态条的文本
EnableDocking 允许一个控件条停靠
DockControlBar 停靠一个控件条
FloatControlBar 浮动一个控件条
BeginModalState 将框架窗口设置为模态
EndModalState 结束框架窗口的模态状态,用BeginModalState使无效的窗口可用
InModalState 返回一个表明框架窗口是否处于模态状态
ShowOwnedWindows 显示所有CFrameWnd对象的后代窗口
RecalcLayout 重新设置CFrameWnd对象的控件条的位置

可重载函数

OnCreateClient 为框架构造一个用户窗口
OnSetPreviewMode 设置应用的主框架成为或退出预打印模式
GetMessageBar 返回一个属于框架窗口的状态条指针
NegotiateBorderSpace 调整框架窗口中的边框空白

命令处理

OnContextHelp 处理相应项的SHIFT+F1帮助

相关百科
返回顶部
产品求购 求购