|
3.5 几种窗口类型 3.5.1 框架窗口 框架窗口为应用程序的用户界面提供结构框架,它是应用程序的主窗口,负责管理其包容的窗口,一个应用程序的最顶层的框架窗口是应用程序启动时创建的第一个窗口。 CFrameWnd CMDIFrameWnd CMDIChildWnd CDialog 要生成一个单文档窗口,主窗口就必须从CFrameWnd派生;要生成一个多文档窗口,主窗口就必须从CMDIFrameWnd派生,而且其中的子窗口必须从CMDIChildWnd派生出来;而基于对话框的窗口程序就要从CDialog派生出主窗口类。 子窗口 父窗口 弹出式窗口 3.5.2窗口的创建 窗口的创建分为两步:第一步是用new创建一个C++的窗口对象,但是此时只是初始化窗口的数据成员,并没有真正创建窗口(这一点与一般的对象有所不同)。 //第一步:创建一个C++对象,其中CMainFrame是从CFrameWnd派生的对象。 CMainFrame* pMyFrame=new CMainFrame();//用new操作符创建窗口对象 或 CMainFrame MyFrame;//定义一个窗口对象,自动调用其构造函数 第二步是创建窗口。CFrameWnd的Create成员函数把窗口给做出来,并将其HWND保存在C++对象的公共数据成员m_hWnd中。 //第二步:创建窗口 pMyFrame->Create(NULL,“My Frame Window”); 或 MyFrame.Create(NULL,“My Frame Window”); Create函数的原形如下:
Create函数第一个参数为窗口注册类名,它指定了窗口的图标和类风格。这里我们使用NULL做为其值,表明使用缺省属性。第二个参数为窗口标题。其余几个参数指定了窗口的风格、大小、父窗口、菜单名等。 这个函数看起来比较复杂,对于CFrameWnd派生出来的窗口,我们可以使用LoadFrame从资源文件中创建窗口,它只需要一个参数。 pMyFrame->LoadFrame(IDR_FRAME); LoadFrame使用该参数从资源中获取许多默认值,包括主边框窗口的标题、图标、菜单、加速键等。但是,在使用LoadFrame时,必须确保标题字符串、图标、菜单、加速键等资源使用同一个ID标识符(在本例中,我们使用IDR_FRAME)。 提示:在Hello程序的InitInstance中我们看不到创建窗口的过程。实际上,在 pDocTemplate = new CSingleDocTemplate( IDR_MAINFRAME, RUNTIME_CLASS(CHelloDoc), RUNTIME_CLASS(CMainFrame), // main SDI frame window RUNTIME_CLASS(CHelloView));
AddDocTemplate(pDocTemplate);
程序片段中,我们看到,CSingleDocTemplate构造函数的第二个参数就是IDR_MAINFRAME。在构造函数内部,已经通过调用m_pMainWnd->LoadFrame(IDR_MAINFRAME),完成了应用程序主窗口的创建过程。 m_pMainWnd->ShowWindow(SW_SHOWMAXIMIZED); 在MainFrm.cpp中,我们还看到CMainFrame类有一个OnCreate方法。OnCreate成员函数定义如清单3.3。当调用Create或CreateEx时,操作系统会向窗口发送一条WM_CREATE消息。这一函数就是用来响应WM_CREATE消息的。 清单3.3 OnCreate成员函数定义 int CMainFrame::OnCreate(LPCREATESTRUCT lpCreateStruct) { if (CFrameWnd::OnCreate(lpCreateStruct) == -1) return -1;
if (!m_wndToolBar.Create(this) || !m_wndToolBar.LoadToolBar(IDR_MAINFRAME)) { TRACE0("Failed to create toolbar\n"); return -1; // fail to create } if (!m_wndStatusBar.Create(this) || !m_wndStatusBar.SetIndicators(indicators, sizeof(indicators)/sizeof(UINT))) { TRACE0("Failed to create status bar\n"); return -1; // fail to create } // TODO: Remove this if you don't want tool tips or a resizeable toolbar m_wndToolBar.SetBarStyle(m_wndToolBar.GetBarStyle() | CBRS_TOOLTIPS | CBRS_FLYBY | CBRS_SIZE_DYNAMIC); // TODO: Delete these three lines if you don't want the toolbar to // be dockable m_wndToolBar.EnableDocking(CBRS_ALIGN_ANY); EnableDocking(CBRS_ALIGN_ANY); DockControlBar(&m_wndToolBar); return 0; } 在OnCreate函数中,首先调用CFrameWnd的缺省处理方法OnCreate完成窗口创建工作。后面是应用程序主窗口的特定工作,在上面程序中,创建了工具条和状态栏(有关工具条和状态栏编程参见下一章有关内容)。可以在此处加入一些初始化工作,如从INI文件中载入设置,显示Splash Window(启动画面)等。 3.5.3 注册窗口 在传统的Windows C程序中,送给一个窗口的所有消息是在它的窗口函数中处理的。把一个窗口同它的窗口函数联系起来的过程称为注册窗口类。注册窗口包括对窗口指定一个窗口函数(给出窗口函数的指针)以及设定窗口的光标、背景刷子等内容。一个注册窗口类可以被多个窗口共享。注册窗口通过调用API函数RegisterClass来完成。 BOOL CMainFrame::PreCreateWindow(CREATESTRUCT& cs) { // TODO: Modify the Window class or styles here by modifying // the CREATESTRUCT cs UINT ClassStyle=CS_VREDRAW|CS_HREDRAW; cs.style=cs.style&(~FWS_ADDTOTITLE); cs.lpszClass = AfxRegisterWndClass(ClassStyle, AfxGetApp()->LoadStandardCursor(IDC_ARROW), (HBRUSH)(COLOR_WINDOW+1),//for brush AfxGetApp()->LoadIcon(IDR_MAINFRAME)); return TRUE; } 注册窗口在CFrameWnd的PreCreateWnd方法中完成。从成员函数名字PreCreateWindow中就可以看出来,注册窗口的工作必须在调用Create函数创建窗口之前完成。其中cs.style=cs.style&(~FWS_ADDTOTITLE)指定窗口标题风格,关闭自动添加文档标题的功能。AfxRegisterWndClass指定窗口使用箭头光标、背景刷子使用比窗口颜色标号大一的颜色、图标使用IDR_MAINFRAME标识符指定的图标(当然也可以使用其它图标)。用上面的程序段替换Hello程序MainFrm.cpp中的PreCreateWindow成员函数定义,并重新编译和运行程序。此时,窗口标题变成了Hello,原来令人讨厌的“Untitled-”没有了,因为窗口风格中关闭自动添加当前文件名的风格。 3.5.4 关闭和销毁窗口 框架窗口不仅维护窗口的创建,还管理着窗口的关闭和销毁过程。关闭窗口时,操作系统依次向被关闭的窗口发送WM_CLOSE和WM_DESTROY消息。WM_CLOSE消息的缺省处理函数OnClose将调用DestroyWindow,来销毁窗口;最后,框架调用窗口的析构函数作清理工作并删除C++窗口对象。 OnClose()常用功能:保存窗口的一些状态、工具条状态,提示保存未保存的数据等等。 void CMainFrame::OnClose() { SaveBarState( "MyDockState" );//保存工具条状态 CFrameWnd::OnClose(); } 3.5.5 窗口激活 活动窗口必定是一个没有父窗口的顶层窗口,包括框架窗口和对话框。当顶层窗口被激活时,Windows向窗口发送WM_ACTIVATE消息,对此消息的缺省处理是将活动窗口设为有输入焦点。
作者: 不详, 来源: Visual C++王朝 |